OSSP CVS Repository

ossp - Check-in [5602]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 5602
Date: 2006-Apr-04 16:09:44 (local)
2006-Apr-04 14:09:44 (UTC)
User:rse
Branch:
Comment: Import new upstream version: Mozilla JavaScript (SpiderMonkey) 1.6 as of 2006-07-24
Tickets:
Inspections:
Files:
ossp-pkg/js/src/js.c      1.1.1.1->removed
ossp-pkg/js/src/jsapi.c      1.1.1.1->removed
ossp-pkg/js/src/jsapi.h      ->removed
ossp-pkg/js/src/jsatom.c      1.1.1.1->removed
ossp-pkg/js/src/jscntxt.c      1.1.1.1->removed
ossp-pkg/js/src/jsinterp.c      1.1.1.1->removed
ossp-pkg/js/src/jsprf.c      1.1.1.1->removed
ossp-pkg/js/src/jspubtd.h      1.1.1.1->removed
ossp-pkg/js/src/jsstr.c      ->removed

ossp-pkg/js/src/js.c 1.1.1.1 -> 1.1.1.2

--- js.c 2006/01/06 16:49:15     1.1.1.1
+++ js.c 2006/04/04 14:09:44     1.1.1.2
@@ -548,12 +548,6 @@
     return JS_TRUE;
 }
 
-static void
-my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
-
-static void
-my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
-
 static JSBool
 Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -563,7 +557,6 @@
     JSScript *script;
     JSBool ok;
     jsval result;
-    JSErrorReporter older;
     uint32 oldopts;
 
     for (i = 0; i < argc; i++) {
@@ -573,7 +566,6 @@
         argv[i] = STRING_TO_JSVAL(str);
         filename = JS_GetStringBytes(str);
         errno = 0;
-        older = JS_SetErrorReporter(cx, my_LoadErrorReporter);
         oldopts = JS_GetOptions(cx);
         JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
         script = JS_CompileFile(cx, obj, filename);
@@ -586,7 +578,6 @@
             JS_DestroyScript(cx, script);
         }
         JS_SetOptions(cx, oldopts);
-        JS_SetErrorReporter(cx, older);
         if (!ok)
             return JS_FALSE;
     }
@@ -1565,6 +1556,54 @@
     return JS_NewNumberValue(cx, i, rval);
 }
 
+static JSBool
+StringsAreUtf8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval)
+{
+    *rval = JS_CStringsAreUTF8() ? 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},
@@ -1578,6 +1617,8 @@
     {"untrap",          Untrap,         2},
     {"line2pc",         LineToPC,       0},
     {"pc2line",         PCToLine,       0},
+    {"stringsAreUtf8",  StringsAreUtf8, 0},
+    {"testUtf8",        TestUtf8,       1},
 #ifdef DEBUG
     {"dis",             Disassemble,    1},
     {"dissrc",          DisassWithSrc,  1},
@@ -1617,6 +1658,8 @@
     "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",
@@ -1644,14 +1687,14 @@
 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
@@ -1923,22 +1966,6 @@
 }
 
 static void
-my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
-{
-    if (!report) {
-        fprintf(gErrFile, "%s\n", message);
-        return;
-    }
-
-    /* Ignore any exceptions */
-    if (JSREPORT_IS_EXCEPTION(report->flags))
-        return;
-
-    /* Otherwise, fall back to the ordinary error reporter. */
-    my_ErrorReporter(cx, message, report);
-}
-
-static void
 my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     int i, j, k, n;


ossp-pkg/js/src/jsapi.c 1.1.1.1 -> 1.1.1.2

--- jsapi.c      2006/06/16 02:01:22     1.1.1.1
+++ jsapi.c      2006/04/04 14:09:44     1.1.1.2
@@ -884,6 +884,10 @@
     /* XXXbe give the GC or another request calling it a chance to run here?
              Assumes FIFO scheduling */
     JS_LOCK_GC(rt);
+    if (rt->gcThread != cx->thread) {
+        while (rt->gcLevel > 0)
+            JS_AWAIT_GC_DONE(rt);
+    }
     rt->requestCount++;
     JS_UNLOCK_GC(rt);
 }
@@ -1465,7 +1469,7 @@
 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
 {
     jsint i, length;
-    
+
     i = *ip;
     length = ida->length;
     if (i >= length) {
@@ -1843,7 +1847,7 @@
     bytes = rt->gcBytes;
     lastBytes = rt->gcLastBytes;
     if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
-        rt->gcMallocBytes > rt->gcMaxMallocBytes) {
+        rt->gcMallocBytes > rt->gcMaxBytes) {
         /*
          * Run the GC if we have half again as many bytes of GC-things as
          * the last time we GC'd, or if we have malloc'd more bytes through
@@ -1877,19 +1881,6 @@
     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)
 {
@@ -2295,7 +2286,7 @@
     scope = js_GetMutableScope(cx, obj);
     if (scope)
         SCOPE_SET_SEALED(scope);
-    JS_UNLOCK_SCOPE(cx, scope);
+    JS_UNLOCK_OBJ(cx, obj);
     if (!scope)
         return JS_FALSE;
 
@@ -3200,7 +3191,7 @@
     void *pdata;
     jsint index;
     JSIdArray *ida;
-    
+
     CHECK_REQUEST(cx);
     iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
     if (!iterobj)
@@ -3276,7 +3267,7 @@
         ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
         JS_ASSERT(i <= ida->length);
         if (i == 0) {
-            *idp = JSVAL_VOID; 
+            *idp = JSVAL_VOID;
         } else {
             *idp = ida->vector[--i];
             OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
@@ -3441,12 +3432,6 @@
     return fun->flags;
 }
 
-JS_PUBLIC_API(uint16)
-JS_GetFunctionArity(JSFunction *fun)
-{
-    return fun->nargs;
-}
-
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
 {
@@ -3626,7 +3611,7 @@
     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);
@@ -3644,7 +3629,7 @@
     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,
@@ -3713,7 +3698,7 @@
     JSErrorReporter older;
 
     CHECK_REQUEST(cx);
-    chars = js_InflateString(cx, bytes, length);
+    chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_TRUE;
 
@@ -3836,7 +3821,7 @@
     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,
@@ -3856,7 +3841,7 @@
     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,
@@ -4061,7 +4046,7 @@
     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);
@@ -4080,7 +4065,7 @@
     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,
@@ -4230,15 +4215,16 @@
 {
     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;
@@ -4257,7 +4243,7 @@
     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);
@@ -4277,7 +4263,7 @@
     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);
@@ -4421,6 +4407,30 @@
     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_CStringsAreUTF8()
+{
+#ifdef JS_C_STRINGS_ARE_UTF8
+    return JS_TRUE;
+#else
+    return JS_FALSE;
+#endif
+}
+
 /************************************************************************/
 
 JS_PUBLIC_API(void)
@@ -4502,7 +4512,7 @@
 JS_PUBLIC_API(void)
 JS_ReportOutOfMemory(JSContext *cx)
 {
-    js_ReportOutOfMemory(cx, js_GetErrorMessage);
+    js_ReportOutOfMemory(cx);
 }
 
 JS_PUBLIC_API(JSErrorReporter)
@@ -4528,7 +4538,7 @@
     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);


ossp-pkg/js/src/jsapi.h -> 1.1.1.2

*** /dev/null    Sat Nov 23 05:07:35 2024
--- -    Sat Nov 23 05:07:42 2024
***************
*** 0 ****
--- 1,2014 ----
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  *
+  * ***** BEGIN LICENSE BLOCK *****
+  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+  *
+  * The contents of this file are subject to the Mozilla Public License Version
+  * 1.1 (the "License"); you may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at
+  * http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an "AS IS" basis,
+  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+  * for the specific language governing rights and limitations under the
+  * License.
+  *
+  * The Original Code is Mozilla Communicator client code, released
+  * March 31, 1998.
+  *
+  * The Initial Developer of the Original Code is
+  * Netscape Communications Corporation.
+  * Portions created by the Initial Developer are Copyright (C) 1998
+  * the Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s):
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either of the GNU General Public License Version 2 or later (the "GPL"),
+  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the MPL, indicate your
+  * decision by deleting the provisions above and replace them with the notice
+  * and other provisions required by the GPL or the LGPL. If you do not delete
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the MPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ #ifndef jsapi_h___
+ #define jsapi_h___
+ /*
+  * JavaScript API.
+  */
+ #include <stddef.h>
+ #include <stdio.h>
+ #include "jspubtd.h"
+ 
+ JS_BEGIN_EXTERN_C
+ 
+ /*
+  * Type tags stored in the low bits of a jsval.
+  */
+ #define JSVAL_OBJECT            0x0     /* untagged reference to object */
+ #define JSVAL_INT               0x1     /* tagged 31-bit integer value */
+ #define JSVAL_DOUBLE            0x2     /* tagged reference to double */
+ #define JSVAL_STRING            0x4     /* tagged reference to string */
+ #define JSVAL_BOOLEAN           0x6     /* tagged boolean value */
+ 
+ /* Type tag bitfield length and derived macros. */
+ #define JSVAL_TAGBITS           3
+ #define JSVAL_TAGMASK           JS_BITMASK(JSVAL_TAGBITS)
+ #define JSVAL_TAG(v)            ((v) & JSVAL_TAGMASK)
+ #define JSVAL_SETTAG(v,t)       ((v) | (t))
+ #define JSVAL_CLRTAG(v)         ((v) & ~(jsval)JSVAL_TAGMASK)
+ #define JSVAL_ALIGN             JS_BIT(JSVAL_TAGBITS)
+ 
+ /* Predicates for type testing. */
+ #define JSVAL_IS_OBJECT(v)      (JSVAL_TAG(v) == JSVAL_OBJECT)
+ #define JSVAL_IS_NUMBER(v)      (JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v))
+ #define JSVAL_IS_INT(v)         (((v) & JSVAL_INT) && (v) != JSVAL_VOID)
+ #define JSVAL_IS_DOUBLE(v)      (JSVAL_TAG(v) == JSVAL_DOUBLE)
+ #define JSVAL_IS_STRING(v)      (JSVAL_TAG(v) == JSVAL_STRING)
+ #define JSVAL_IS_BOOLEAN(v)     (JSVAL_TAG(v) == JSVAL_BOOLEAN)
+ #define JSVAL_IS_NULL(v)        ((v) == JSVAL_NULL)
+ #define JSVAL_IS_VOID(v)        ((v) == JSVAL_VOID)
+ #define JSVAL_IS_PRIMITIVE(v)   (!JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v))
+ 
+ /* Objects, strings, and doubles are GC'ed. */
+ #define JSVAL_IS_GCTHING(v)     (!((v) & JSVAL_INT) && !JSVAL_IS_BOOLEAN(v))
+ #define JSVAL_TO_GCTHING(v)     ((void *)JSVAL_CLRTAG(v))
+ #define JSVAL_TO_OBJECT(v)      ((JSObject *)JSVAL_TO_GCTHING(v))
+ #define JSVAL_TO_DOUBLE(v)      ((jsdouble *)JSVAL_TO_GCTHING(v))
+ #define JSVAL_TO_STRING(v)      ((JSString *)JSVAL_TO_GCTHING(v))
+ #define OBJECT_TO_JSVAL(obj)    ((jsval)(obj))
+ #define DOUBLE_TO_JSVAL(dp)     JSVAL_SETTAG((jsval)(dp), JSVAL_DOUBLE)
+ #define STRING_TO_JSVAL(str)    JSVAL_SETTAG((jsval)(str), JSVAL_STRING)
+ 
+ /* Lock and unlock the GC thing held by a jsval. */
+ #define JSVAL_LOCK(cx,v)        (JSVAL_IS_GCTHING(v)                          \
+                                  ? JS_LockGCThing(cx, JSVAL_TO_GCTHING(v))    \
+                                  : JS_TRUE)
+ #define JSVAL_UNLOCK(cx,v)      (JSVAL_IS_GCTHING(v)                          \
+                                  ? JS_UnlockGCThing(cx, JSVAL_TO_GCTHING(v))  \
+                                  : JS_TRUE)
+ 
+ /* Domain limits for the jsval int type. */
+ #define JSVAL_INT_BITS          31
+ #define JSVAL_INT_POW2(n)       ((jsval)1 << (n))
+ #define JSVAL_INT_MIN           ((jsval)1 - JSVAL_INT_POW2(30))
+ #define JSVAL_INT_MAX           (JSVAL_INT_POW2(30) - 1)
+ #define INT_FITS_IN_JSVAL(i)    ((jsuint)((i)+JSVAL_INT_MAX) <= 2*JSVAL_INT_MAX)
+ #define JSVAL_TO_INT(v)         ((jsint)(v) >> 1)
+ #define INT_TO_JSVAL(i)         (((jsval)(i) << 1) | JSVAL_INT)
+ 
+ /* Convert between boolean and jsval. */
+ #define JSVAL_TO_BOOLEAN(v)     ((JSBool)((v) >> JSVAL_TAGBITS))
+ #define BOOLEAN_TO_JSVAL(b)     JSVAL_SETTAG((jsval)(b) << JSVAL_TAGBITS,     \
+                                              JSVAL_BOOLEAN)
+ 
+ /* A private data pointer (2-byte-aligned) can be stored as an int jsval. */
+ #define JSVAL_TO_PRIVATE(v)     ((void *)((v) & ~JSVAL_INT))
+ #define PRIVATE_TO_JSVAL(p)     ((jsval)(p) | JSVAL_INT)
+ 
+ /* Property attributes, set in JSPropertySpec and passed to API functions. */
+ #define JSPROP_ENUMERATE        0x01    /* property is visible to for/in loop */
+ #define JSPROP_READONLY         0x02    /* not settable: assignment is no-op */
+ #define JSPROP_PERMANENT        0x04    /* property cannot be deleted */
+ #define JSPROP_EXPORTED         0x08    /* property is exported from object */
+ #define JSPROP_GETTER           0x10    /* property holds getter function */
+ #define JSPROP_SETTER           0x20    /* property holds setter function */
+ #define JSPROP_SHARED           0x40    /* don't allocate a value slot for this
+                                            property; don't copy the property on
+                                            set of the same-named property in an
+                                            object that delegates to a prototype
+                                            containing this property */
+ #define JSPROP_INDEX            0x80    /* name is actually (jsint) index */
+ 
+ /* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */
+ #define JSFUN_LAMBDA            0x08    /* expressed, not declared, function */
+ #define JSFUN_GETTER            JSPROP_GETTER
+ #define JSFUN_SETTER            JSPROP_SETTER
+ #define JSFUN_BOUND_METHOD      0x40    /* bind this to fun->object's parent */
+ #define JSFUN_HEAVYWEIGHT       0x80    /* activation requires a Call object */
+ #define JSFUN_FLAGS_MASK        0xf8    /* overlay JSFUN_* attributes */
+ 
+ /*
+  * Re-use JSFUN_LAMBDA, which applies only to scripted functions, for use in
+  * JSFunctionSpec arrays that specify generic native prototype methods, i.e.,
+  * methods of a class prototype that are exposed as static methods taking an
+  * extra leading argument: the generic |this| parameter.
+  *
+  * If you set this flag in a JSFunctionSpec struct's flags initializer, then
+  * that struct must live at least as long as the native static method object
+  * created due to this flag by JS_DefineFunctions or JS_InitClass.  Typically
+  * JSFunctionSpec structs are allocated in static arrays.
+  */
+ #define JSFUN_GENERIC_NATIVE    JSFUN_LAMBDA
+ 
+ /*
+  * Well-known JS values.  The extern'd variables are initialized when the
+  * first JSContext is created by JS_NewContext (see below).
+  */
+ #define JSVAL_VOID              INT_TO_JSVAL(0 - JSVAL_INT_POW2(30))
+ #define JSVAL_NULL              OBJECT_TO_JSVAL(0)
+ #define JSVAL_ZERO              INT_TO_JSVAL(0)
+ #define JSVAL_ONE               INT_TO_JSVAL(1)
+ #define JSVAL_FALSE             BOOLEAN_TO_JSVAL(JS_FALSE)
+ #define JSVAL_TRUE              BOOLEAN_TO_JSVAL(JS_TRUE)
+ 
+ /*
+  * Microseconds since the epoch, midnight, January 1, 1970 UTC.  See the
+  * comment in jstypes.h regarding safe int64 usage.
+  */
+ extern JS_PUBLIC_API(int64)
+ JS_Now();
+ 
+ /* Don't want to export data, so provide accessors for non-inline jsvals. */
+ extern JS_PUBLIC_API(jsval)
+ JS_GetNaNValue(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsval)
+ JS_GetNegativeInfinityValue(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsval)
+ JS_GetPositiveInfinityValue(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsval)
+ JS_GetEmptyStringValue(JSContext *cx);
+ 
+ /*
+  * Format is a string of the following characters (spaces are insignificant),
+  * specifying the tabulated type conversions:
+  *
+  *   b      JSBool          Boolean
+  *   c      uint16/jschar   ECMA uint16, Unicode char
+  *   i      int32           ECMA int32
+  *   u      uint32          ECMA uint32
+  *   j      int32           Rounded int32 (coordinate)
+  *   d      jsdouble        IEEE double
+  *   I      jsdouble        Integral IEEE double
+  *   s      char *          C string
+  *   S      JSString *      Unicode string, accessed by a JSString pointer
+  *   W      jschar *        Unicode character vector, 0-terminated (W for wide)
+  *   o      JSObject *      Object reference
+  *   f      JSFunction *    Function private
+  *   v      jsval           Argument value (no conversion)
+  *   *      N/A             Skip this argument (no vararg)
+  *   /      N/A             End of required arguments
+  *
+  * The variable argument list after format must consist of &b, &c, &s, e.g.,
+  * where those variables have the types given above.  For the pointer types
+  * char *, JSString *, and JSObject *, the pointed-at memory returned belongs
+  * to the JS runtime, not to the calling native code.  The runtime promises
+  * to keep this memory valid so long as argv refers to allocated stack space
+  * (so long as the native function is active).
+  *
+  * Fewer arguments than format specifies may be passed only if there is a /
+  * in format after the last required argument specifier and argc is at least
+  * the number of required arguments.  More arguments than format specifies
+  * may be passed without error; it is up to the caller to deal with trailing
+  * unconverted arguments.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
+                     ...);
+ 
+ #ifdef va_start
+ extern JS_PUBLIC_API(JSBool)
+ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
+                       const char *format, va_list ap);
+ #endif
+ 
+ /*
+  * Inverse of JS_ConvertArguments: scan format and convert trailing arguments
+  * into jsvals, GC-rooted if necessary by the JS stack.  Return null on error,
+  * and a pointer to the new argument vector on success.  Also return a stack
+  * mark on success via *markp, in which case the caller must eventually clean
+  * up by calling JS_PopArguments.
+  *
+  * Note that the number of actual arguments supplied is specified exclusively
+  * by format, so there is no argc parameter.
+  */
+ extern JS_PUBLIC_API(jsval *)
+ JS_PushArguments(JSContext *cx, void **markp, const char *format, ...);
+ 
+ #ifdef va_start
+ extern JS_PUBLIC_API(jsval *)
+ JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap);
+ #endif
+ 
+ extern JS_PUBLIC_API(void)
+ JS_PopArguments(JSContext *cx, void *mark);
+ 
+ #ifdef JS_ARGUMENT_FORMATTER_DEFINED
+ 
+ /*
+  * Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}.
+  * The handler function has this signature (see jspubtd.h):
+  *
+  *   JSBool MyArgumentFormatter(JSContext *cx, const char *format,
+  *                              JSBool fromJS, jsval **vpp, va_list *app);
+  *
+  * It should return true on success, and return false after reporting an error
+  * or detecting an already-reported error.
+  *
+  * For a given format string, for example "AA", the formatter is called from
+  * JS_ConvertArgumentsVA like so:
+  *
+  *   formatter(cx, "AA...", JS_TRUE, &sp, &ap);
+  *
+  * sp points into the arguments array on the JS stack, while ap points into
+  * the stdarg.h va_list on the C stack.  The JS_TRUE passed for fromJS tells
+  * the formatter to convert zero or more jsvals at sp to zero or more C values
+  * accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap
+  * (via *app) to point past the converted arguments and their result pointers
+  * on the C stack.
+  *
+  * When called from JS_PushArgumentsVA, the formatter is invoked thus:
+  *
+  *   formatter(cx, "AA...", JS_FALSE, &sp, &ap);
+  *
+  * where JS_FALSE for fromJS means to wrap the C values at ap according to the
+  * format specifier and store them at sp, updating ap and sp appropriately.
+  *
+  * The "..." after "AA" is the rest of the format string that was passed into
+  * JS_{Convert,Push}Arguments{,VA}.  The actual format trailing substring used
+  * in each Convert or PushArguments call is passed to the formatter, so that
+  * one such function may implement several formats, in order to share code.
+  *
+  * Remove just forgets about any handler associated with format.  Add does not
+  * copy format, it points at the string storage allocated by the caller, which
+  * is typically a string constant.  If format is in dynamic storage, it is up
+  * to the caller to keep the string alive until Remove is called.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_AddArgumentFormatter(JSContext *cx, const char *format,
+                         JSArgumentFormatter formatter);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_RemoveArgumentFormatter(JSContext *cx, const char *format);
+ 
+ #endif /* JS_ARGUMENT_FORMATTER_DEFINED */
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_ValueToFunction(JSContext *cx, jsval v);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_ValueToConstructor(JSContext *cx, jsval v);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_ValueToString(JSContext *cx, jsval v);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp);
+ 
+ /*
+  * Convert a value to a number, then to an int32, according to the ECMA rules
+  * for ToInt32.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip);
+ 
+ /*
+  * Convert a value to a number, then to a uint32, according to the ECMA rules
+  * for ToUint32.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip);
+ 
+ /*
+  * Convert a value to a number, then to an int32 if it fits by rounding to
+  * nearest; but failing with an error report if the double is out of range
+  * or unordered.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip);
+ 
+ /*
+  * ECMA ToUint16, for mapping a jsval to a Unicode point.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp);
+ 
+ extern JS_PUBLIC_API(JSType)
+ JS_TypeOfValue(JSContext *cx, jsval v);
+ 
+ extern JS_PUBLIC_API(const char *)
+ JS_GetTypeName(JSContext *cx, JSType type);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Initialization, locking, contexts, and memory allocation.
+  */
+ #define JS_NewRuntime       JS_Init
+ #define JS_DestroyRuntime   JS_Finish
+ #define JS_LockRuntime      JS_Lock
+ #define JS_UnlockRuntime    JS_Unlock
+ 
+ extern JS_PUBLIC_API(JSRuntime *)
+ JS_NewRuntime(uint32 maxbytes);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyRuntime(JSRuntime *rt);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ShutDown(void);
+ 
+ JS_PUBLIC_API(void *)
+ JS_GetRuntimePrivate(JSRuntime *rt);
+ 
+ JS_PUBLIC_API(void)
+ JS_SetRuntimePrivate(JSRuntime *rt, void *data);
+ 
+ #ifdef JS_THREADSAFE
+ 
+ extern JS_PUBLIC_API(void)
+ JS_BeginRequest(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_EndRequest(JSContext *cx);
+ 
+ /* Yield to pending GC operations, regardless of request depth */
+ extern JS_PUBLIC_API(void)
+ JS_YieldRequest(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsrefcount)
+ JS_SuspendRequest(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth);
+ 
+ #endif /* JS_THREADSAFE */
+ 
+ extern JS_PUBLIC_API(void)
+ JS_Lock(JSRuntime *rt);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_Unlock(JSRuntime *rt);
+ 
+ extern JS_PUBLIC_API(JSContext *)
+ JS_NewContext(JSRuntime *rt, size_t stackChunkSize);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyContext(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyContextNoGC(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyContextMaybeGC(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void *)
+ JS_GetContextPrivate(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_SetContextPrivate(JSContext *cx, void *data);
+ 
+ extern JS_PUBLIC_API(JSRuntime *)
+ JS_GetRuntime(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSContext *)
+ JS_ContextIterator(JSRuntime *rt, JSContext **iterp);
+ 
+ extern JS_PUBLIC_API(JSVersion)
+ JS_GetVersion(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSVersion)
+ JS_SetVersion(JSContext *cx, JSVersion version);
+ 
+ extern JS_PUBLIC_API(const char *)
+ JS_VersionToString(JSVersion version);
+ 
+ extern JS_PUBLIC_API(JSVersion)
+ JS_StringToVersion(const char *string);
+ 
+ /*
+  * JS options are orthogonal to version, and may be freely composed with one
+  * another as well as with version.
+  *
+  * JSOPTION_VAROBJFIX is recommended -- see the comments associated with the
+  * prototypes for JS_ExecuteScript, JS_EvaluateScript, etc.
+  */
+ #define JSOPTION_STRICT         JS_BIT(0)       /* warn on dubious practice */
+ #define JSOPTION_WERROR         JS_BIT(1)       /* convert warning to error */
+ #define JSOPTION_VAROBJFIX      JS_BIT(2)       /* make JS_EvaluateScript use
+                                                    the last object on its 'obj'
+                                                    param's scope chain as the
+                                                    ECMA 'variables object' */
+ #define JSOPTION_PRIVATE_IS_NSISUPPORTS \
+                                 JS_BIT(3)       /* context private data points
+                                                    to an nsISupports subclass */
+ #define JSOPTION_COMPILE_N_GO   JS_BIT(4)       /* caller of JS_Compile*Script
+                                                    promises to execute compiled
+                                                    script once only; enables
+                                                    compile-time scope chain
+                                                    resolution of consts. */
+ #define JSOPTION_ATLINE         JS_BIT(5)       /* //@line number ["filename"]
+                                                    option supported for the
+                                                    XUL preprocessor and kindred
+                                                    beasts. */
+ #define JSOPTION_XML            JS_BIT(6)       /* EMCAScript for XML support:
+                                                    parse <!-- --> as a token,
+                                                    not backward compatible with
+                                                    the comment-hiding hack used
+                                                    in HTML script tags. */
+ #define JSOPTION_NATIVE_BRANCH_CALLBACK \
+                                 JS_BIT(7)       /* the branch callback set by
+                                                    JS_SetBranchCallback may be
+                                                    called with a null script
+                                                    parameter, by native code
+                                                    that loops intensively */
+ 
+ extern JS_PUBLIC_API(uint32)
+ JS_GetOptions(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(uint32)
+ JS_SetOptions(JSContext *cx, uint32 options);
+ 
+ extern JS_PUBLIC_API(uint32)
+ JS_ToggleOptions(JSContext *cx, uint32 options);
+ 
+ extern JS_PUBLIC_API(const char *)
+ JS_GetImplementationVersion(void);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetGlobalObject(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_SetGlobalObject(JSContext *cx, JSObject *obj);
+ 
+ /*
+  * Initialize standard JS class constructors, prototypes, and any top-level
+  * functions and constants associated with the standard classes (e.g. isNaN
+  * for Number).
+  *
+  * NB: This sets cx's global object to obj if it was null.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_InitStandardClasses(JSContext *cx, JSObject *obj);
+ 
+ /*
+  * Resolve id, which must contain either a string or an int, to a standard
+  * class name in obj if possible, defining the class's constructor and/or
+  * prototype and storing true in *resolved.  If id does not name a standard
+  * class or a top-level property induced by initializing a standard class,
+  * store false in *resolved and just return true.  Return false on error,
+  * as usual for JSBool result-typed API entry points.
+  *
+  * This API can be called directly from a global object class's resolve op,
+  * to define standard classes lazily.  The class's enumerate op should call
+  * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in
+  * loops any classes not yet resolved lazily.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
+                         JSBool *resolved);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj);
+ 
+ /*
+  * Enumerate any already-resolved standard class ids into ida, or into a new
+  * JSIdArray if ida is null.  Return the augmented array on success, null on
+  * failure with ida (if it was non-null on entry) destroyed.
+  */
+ extern JS_PUBLIC_API(JSIdArray *)
+ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
+                                     JSIdArray *ida);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetScopeChain(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void *)
+ JS_malloc(JSContext *cx, size_t nbytes);
+ 
+ extern JS_PUBLIC_API(void *)
+ JS_realloc(JSContext *cx, void *p, size_t nbytes);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_free(JSContext *cx, void *p);
+ 
+ extern JS_PUBLIC_API(char *)
+ JS_strdup(JSContext *cx, const char *s);
+ 
+ extern JS_PUBLIC_API(jsdouble *)
+ JS_NewDouble(JSContext *cx, jsdouble d);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval);
+ 
+ /*
+  * A JS GC root is a pointer to a JSObject *, JSString *, or jsdouble * that
+  * itself points into the GC heap (more recently, we support this extension:
+  * a root may be a pointer to a jsval v for which JSVAL_IS_GCTHING(v) is true).
+  *
+  * Therefore, you never pass JSObject *obj to JS_AddRoot(cx, obj).  You always
+  * call JS_AddRoot(cx, &obj), passing obj by reference.  And later, before obj
+  * or the structure it is embedded within goes out of scope or is freed, you
+  * must call JS_RemoveRoot(cx, &obj).
+  *
+  * Also, use JS_AddNamedRoot(cx, &structPtr->memberObj, "structPtr->memberObj")
+  * in preference to JS_AddRoot(cx, &structPtr->memberObj), in order to identify
+  * roots by their source callsites.  This way, you can find the callsite while
+  * debugging if you should fail to do JS_RemoveRoot(cx, &structPtr->memberObj)
+  * before freeing structPtr's memory.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_AddRoot(JSContext *cx, void *rp);
+ 
+ #ifdef NAME_ALL_GC_ROOTS
+ #define JS_DEFINE_TO_TOKEN(def) #def
+ #define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def)
+ #define JS_AddRoot(cx,rp) JS_AddNamedRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+ #endif
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_AddNamedRoot(JSContext *cx, void *rp, const char *name);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_RemoveRoot(JSContext *cx, void *rp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_RemoveRootRT(JSRuntime *rt, void *rp);
+ 
+ /*
+  * The last GC thing of each type (object, string, double, external string
+  * types) created on a given context is kept alive until another thing of the
+  * same type is created, using a newborn root in the context.  These newborn
+  * roots help native code protect newly-created GC-things from GC invocations
+  * activated before those things can be rooted using local or global roots.
+  *
+  * However, the newborn roots can also entrain great gobs of garbage, so the
+  * JS_GC entry point clears them for the context on which GC is being forced.
+  * Embeddings may need to do likewise for all contexts.
+  *
+  * See the scoped local root API immediately below for a better way to manage
+  * newborns in cases where native hooks (functions, getters, setters, etc.)
+  * create many GC-things, potentially without connecting them to predefined
+  * local roots such as *rval or argv[i] in an active native function.  Using
+  * JS_EnterLocalRootScope disables updating of the context's per-gc-thing-type
+  * newborn roots, until control flow unwinds and leaves the outermost nesting
+  * local root scope.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_ClearNewbornRoots(JSContext *cx);
+ 
+ /*
+  * Scoped local root management allows native functions, getter/setters, etc.
+  * to avoid worrying about the newborn root pigeon-holes, overloading local
+  * roots allocated in argv and *rval, or ending up having to call JS_Add*Root
+  * and JS_RemoveRoot to manage global roots temporarily.
+  *
+  * Instead, calling JS_EnterLocalRootScope and JS_LeaveLocalRootScope around
+  * the body of the native hook causes the engine to allocate a local root for
+  * each newborn created in between the two API calls, using a local root stack
+  * associated with cx.  For example:
+  *
+  *    JSBool
+  *    my_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+  *    {
+  *        JSBool ok;
+  *
+  *        if (!JS_EnterLocalRootScope(cx))
+  *            return JS_FALSE;
+  *        ok = my_GetPropertyBody(cx, obj, id, vp);
+  *        JS_LeaveLocalRootScope(cx);
+  *        return ok;
+  *    }
+  *
+  * NB: JS_LeaveLocalRootScope must be called once for every prior successful
+  * call to JS_EnterLocalRootScope.  If JS_EnterLocalRootScope fails, you must
+  * not make the matching JS_LeaveLocalRootScope call.
+  *
+  * In case a native hook allocates many objects or other GC-things, but the
+  * native protects some of those GC-things by storing them as property values
+  * in an object that is itself protected, the hook can call JS_ForgetLocalRoot
+  * to free the local root automatically pushed for the now-protected GC-thing.
+  *
+  * JS_ForgetLocalRoot works on any GC-thing allocated in the current local
+  * root scope, but it's more time-efficient when called on references to more
+  * recently created GC-things.  Calling it successively on other than the most
+  * recently allocated GC-thing will tend to average the time inefficiency, and
+  * may risk O(n^2) growth rate, but in any event, you shouldn't allocate too
+  * many local roots if you can root as you go (build a tree of objects from
+  * the top down, forgetting each latest-allocated GC-thing immediately upon
+  * linking it to its parent).
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_EnterLocalRootScope(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_LeaveLocalRootScope(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ForgetLocalRoot(JSContext *cx, void *thing);
+ 
+ #ifdef DEBUG
+ extern JS_PUBLIC_API(void)
+ JS_DumpNamedRoots(JSRuntime *rt,
+                   void (*dump)(const char *name, void *rp, void *data),
+                   void *data);
+ #endif
+ 
+ /*
+  * Call JS_MapGCRoots to map the GC's roots table using map(rp, name, data).
+  * The root is pointed at by rp; if the root is unnamed, name is null; data is
+  * supplied from the third parameter to JS_MapGCRoots.
+  *
+  * The map function should return JS_MAP_GCROOT_REMOVE to cause the currently
+  * enumerated root to be removed.  To stop enumeration, set JS_MAP_GCROOT_STOP
+  * in the return value.  To keep on mapping, return JS_MAP_GCROOT_NEXT.  These
+  * constants are flags; you can OR them together.
+  *
+  * This function acquires and releases rt's GC lock around the mapping of the
+  * roots table, so the map function should run to completion in as few cycles
+  * as possible.  Of course, map cannot call JS_GC, JS_MaybeGC, JS_BeginRequest,
+  * or any JS API entry point that acquires locks, without double-tripping or
+  * deadlocking on the GC lock.
+  *
+  * JS_MapGCRoots returns the count of roots that were successfully mapped.
+  */
+ #define JS_MAP_GCROOT_NEXT      0       /* continue mapping entries */
+ #define JS_MAP_GCROOT_STOP      1       /* stop mapping entries */
+ #define JS_MAP_GCROOT_REMOVE    2       /* remove and free the current entry */
+ 
+ typedef intN
+ (* JS_DLL_CALLBACK JSGCRootMapFun)(void *rp, const char *name, void *data);
+ 
+ extern JS_PUBLIC_API(uint32)
+ JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LockGCThing(JSContext *cx, void *thing);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LockGCThingRT(JSRuntime *rt, void *thing);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_UnlockGCThing(JSContext *cx, void *thing);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_UnlockGCThingRT(JSRuntime *rt, void *thing);
+ 
+ /*
+  * For implementors of JSObjectOps.mark, to mark a GC-thing reachable via a
+  * property or other strong ref identified for debugging purposes by name.
+  * The name argument's storage needs to live only as long as the call to
+  * this routine.
+  *
+  * The final arg is used by GC_MARK_DEBUG code to build a ref path through
+  * the GC's live thing graph.  Implementors of JSObjectOps.mark should pass
+  * its final arg through to this function when marking all GC-things that are
+  * directly reachable from the object being marked.
+  *
+  * See the JSMarkOp typedef in jspubtd.h, and the JSObjectOps struct below.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_GC(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_MaybeGC(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSGCCallback)
+ JS_SetGCCallback(JSContext *cx, JSGCCallback cb);
+ 
+ extern JS_PUBLIC_API(JSGCCallback)
+ JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IsAboutToBeFinalized(JSContext *cx, void *thing);
+ 
+ /*
+  * Add a finalizer for external strings created by JS_NewExternalString (see
+  * below) using a type-code returned from this function, and that understands
+  * how to free or release the memory pointed at by JS_GetStringChars(str).
+  *
+  * Return a nonnegative type index if there is room for finalizer in the
+  * global GC finalizers table, else return -1.  If the engine is compiled
+  * JS_THREADSAFE and used in a multi-threaded environment, this function must
+  * be invoked on the primordial thread only, at startup -- or else the entire
+  * program must single-thread itself while loading a module that calls this
+  * function.
+  */
+ extern JS_PUBLIC_API(intN)
+ JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer);
+ 
+ /*
+  * Remove finalizer from the global GC finalizers table, returning its type
+  * code if found, -1 if not found.
+  *
+  * As with JS_AddExternalStringFinalizer, there is a threading restriction
+  * if you compile the engine JS_THREADSAFE: this function may be called for a
+  * given finalizer pointer on only one thread; different threads may call to
+  * remove distinct finalizers safely.
+  *
+  * You must ensure that all strings with finalizer's type have been collected
+  * before calling this function.  Otherwise, string data will be leaked by the
+  * GC, for want of a finalizer to call.
+  */
+ extern JS_PUBLIC_API(intN)
+ JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer);
+ 
+ /*
+  * Create a new JSString whose chars member refers to external memory, i.e.,
+  * memory requiring special, type-specific finalization.  The type code must
+  * be a nonnegative return value from JS_AddExternalStringFinalizer.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type);
+ 
+ /*
+  * Returns the external-string finalizer index for this string, or -1 if it is
+  * an "internal" (native to JS engine) string.
+  */
+ extern JS_PUBLIC_API(intN)
+ JS_GetExternalStringGCType(JSRuntime *rt, JSString *str);
+ 
+ /*
+  * Sets maximum (if stack grows upward) or minimum (downward) legal stack byte
+  * address in limitAddr for the thread or process stack used by cx.  To disable
+  * stack size checking, pass 0 for limitAddr.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Classes, objects, and properties.
+  */
+ 
+ /* For detailed comments on the function pointer types, see jspubtd.h. */
+ struct JSClass {
+     const char          *name;
+     uint32              flags;
+ 
+     /* Mandatory non-null function pointer members. */
+     JSPropertyOp        addProperty;
+     JSPropertyOp        delProperty;
+     JSPropertyOp        getProperty;
+     JSPropertyOp        setProperty;
+     JSEnumerateOp       enumerate;
+     JSResolveOp         resolve;
+     JSConvertOp         convert;
+     JSFinalizeOp        finalize;
+ 
+     /* Optionally non-null members start here. */
+     JSGetObjectOps      getObjectOps;
+     JSCheckAccessOp     checkAccess;
+     JSNative            call;
+     JSNative            construct;
+     JSXDRObjectOp       xdrObject;
+     JSHasInstanceOp     hasInstance;
+     JSMarkOp            mark;
+     JSReserveSlotsOp    reserveSlots;
+ };
+ 
+ struct JSExtendedClass {
+     JSClass             base;
+     JSEqualityOp        equality;
+     JSObjectOp          outerObject;
+     JSObjectOp          innerObject;
+     jsword              reserved0;
+     jsword              reserved1;
+     jsword              reserved2;
+     jsword              reserved3;
+     jsword              reserved4;
+ };
+ 
+ #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
+ #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
+ #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
+ #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
+ #define JSCLASS_SHARE_ALL_PROPERTIES    (1<<4)  /* all properties are SHARED */
+ #define JSCLASS_NEW_RESOLVE_GETS_START  (1<<5)  /* JSNewResolveOp gets starting
+                                                    object in prototype chain
+                                                    passed in via *objp in/out
+                                                    parameter */
+ #define JSCLASS_CONSTRUCT_PROTOTYPE     (1<<6)  /* call constructor on class
+                                                    prototype */
+ #define JSCLASS_DOCUMENT_OBSERVER       (1<<7)  /* DOM document observer */
+ 
+ /*
+  * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
+  * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
+  * n is a constant in [1, 255].  Reserved slots are indexed from 0 to n-1.
+  */
+ #define JSCLASS_RESERVED_SLOTS_SHIFT    8       /* room for 8 flags below */
+ #define JSCLASS_RESERVED_SLOTS_WIDTH    8       /* and 16 above this field */
+ #define JSCLASS_RESERVED_SLOTS_MASK     JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
+ #define JSCLASS_HAS_RESERVED_SLOTS(n)   (((n) & JSCLASS_RESERVED_SLOTS_MASK)  \
+                                          << JSCLASS_RESERVED_SLOTS_SHIFT)
+ #define JSCLASS_RESERVED_SLOTS(clasp)   (((clasp)->flags                      \
+                                           >> JSCLASS_RESERVED_SLOTS_SHIFT)    \
+                                          & JSCLASS_RESERVED_SLOTS_MASK)
+ 
+ #define JSCLASS_HIGH_FLAGS_SHIFT        (JSCLASS_RESERVED_SLOTS_SHIFT +       \
+                                          JSCLASS_RESERVED_SLOTS_WIDTH)
+ 
+ /* True if JSClass is really a JSExtendedClass. */
+ #define JSCLASS_IS_EXTENDED             (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
+ 
+ /* Initializer for unused members of statically initialized JSClass structs. */
+ #define JSCLASS_NO_OPTIONAL_MEMBERS     0,0,0,0,0,0,0,0
+ #define JSCLASS_NO_RESERVED_MEMBERS     0,0,0,0,0
+ 
+ /* For detailed comments on these function pointer types, see jspubtd.h. */
+ struct JSObjectOps {
+     /* Mandatory non-null function pointer members. */
+     JSNewObjectMapOp    newObjectMap;
+     JSObjectMapOp       destroyObjectMap;
+     JSLookupPropOp      lookupProperty;
+     JSDefinePropOp      defineProperty;
+     JSPropertyIdOp      getProperty;
+     JSPropertyIdOp      setProperty;
+     JSAttributesOp      getAttributes;
+     JSAttributesOp      setAttributes;
+     JSPropertyIdOp      deleteProperty;
+     JSConvertOp         defaultValue;
+     JSNewEnumerateOp    enumerate;
+     JSCheckAccessIdOp   checkAccess;
+ 
+     /* Optionally non-null members start here. */
+     JSObjectOp          thisObject;
+     JSPropertyRefOp     dropProperty;
+     JSNative            call;
+     JSNative            construct;
+     JSXDRObjectOp       xdrObject;
+     JSHasInstanceOp     hasInstance;
+     JSSetObjectSlotOp   setProto;
+     JSSetObjectSlotOp   setParent;
+     JSMarkOp            mark;
+     JSFinalizeOp        clear;
+     JSGetRequiredSlotOp getRequiredSlot;
+     JSSetRequiredSlotOp setRequiredSlot;
+ };
+ 
+ struct JSXMLObjectOps {
+     JSObjectOps         base;
+     JSGetMethodOp       getMethod;
+     JSSetMethodOp       setMethod;
+     JSEnumerateValuesOp enumerateValues;
+     JSEqualityOp        equality;
+     JSConcatenateOp     concatenate;
+ };
+ 
+ /*
+  * Classes that expose JSObjectOps via a non-null getObjectOps class hook may
+  * derive a property structure from this struct, return a pointer to it from
+  * lookupProperty and defineProperty, and use the pointer to avoid rehashing
+  * in getAttributes and setAttributes.
+  *
+  * The jsid type contains either an int jsval (see JSVAL_IS_INT above), or an
+  * internal pointer that is opaque to users of this API, but which users may
+  * convert from and to a jsval using JS_ValueToId and JS_IdToValue.
+  */
+ struct JSProperty {
+     jsid id;
+ };
+ 
+ struct JSIdArray {
+     jsint length;
+     jsid  vector[1];    /* actually, length jsid words */
+ };
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ValueToId(JSContext *cx, jsval v, jsid *idp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IdToValue(JSContext *cx, jsid id, jsval *vp);
+ 
+ /*
+  * The magic XML namespace id is int-tagged, but not a valid integer jsval.
+  * Global object classes in embeddings that enable JS_HAS_XML_SUPPORT (E4X)
+  * should handle this id specially before converting id via JSVAL_TO_INT.
+  */
+ #define JS_DEFAULT_XML_NAMESPACE_ID ((jsid) JSVAL_VOID)
+ 
+ /*
+  * JSNewResolveOp flag bits.
+  */
+ #define JSRESOLVE_QUALIFIED     0x01    /* resolve a qualified property id */
+ #define JSRESOLVE_ASSIGNING     0x02    /* resolve on the left of assignment */
+ #define JSRESOLVE_DETECTING     0x04    /* 'if (o.p)...' or '(o.p) ?...:...' */
+ #define JSRESOLVE_DECLARING     0x08    /* var, const, or function prolog op */
+ #define JSRESOLVE_CLASSNAME     0x10    /* class name used when constructing */
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EnumerateStub(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_FinalizeStub(JSContext *cx, JSObject *obj);
+ 
+ struct JSConstDoubleSpec {
+     jsdouble        dval;
+     const char      *name;
+     uint8           flags;
+     uint8           spare[3];
+ };
+ 
+ /*
+  * To define an array element rather than a named property member, cast the
+  * element's index to (const char *) and initialize name with it, and set the
+  * JSPROP_INDEX bit in flags.
+  */
+ struct JSPropertySpec {
+     const char      *name;
+     int8            tinyid;
+     uint8           flags;
+     JSPropertyOp    getter;
+     JSPropertyOp    setter;
+ };
+ 
+ struct JSFunctionSpec {
+     const char      *name;
+     JSNative        call;
+     uint8           nargs;
+     uint8           flags;
+     uint16          extra;      /* number of arg slots for local GC roots */
+ };
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+              JSClass *clasp, JSNative constructor, uintN nargs,
+              JSPropertySpec *ps, JSFunctionSpec *fs,
+              JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
+ 
+ #ifdef JS_THREADSAFE
+ extern JS_PUBLIC_API(JSClass *)
+ JS_GetClass(JSContext *cx, JSObject *obj);
+ 
+ #define JS_GET_CLASS(cx,obj) JS_GetClass(cx, obj)
+ #else
+ extern JS_PUBLIC_API(JSClass *)
+ JS_GetClass(JSObject *obj);
+ 
+ #define JS_GET_CLASS(cx,obj) JS_GetClass(obj)
+ #endif
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
+ 
+ extern JS_PUBLIC_API(void *)
+ JS_GetPrivate(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetPrivate(JSContext *cx, JSObject *obj, void *data);
+ 
+ extern JS_PUBLIC_API(void *)
+ JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
+                       jsval *argv);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetPrototype(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetParent(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetConstructor(JSContext *cx, JSObject *proto);
+ 
+ /*
+  * Get a unique identifier for obj, good for the lifetime of obj (even if it
+  * is moved by a copying GC).  Return false on failure (likely out of memory),
+  * and true with *idp containing the unique id on success.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+                    JSObject *parent);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
+                                 JSObject *parent, uintN argc, jsval *argv);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
+                 JSObject *proto, uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+                   JSPropertyOp getter, JSPropertyOp setter, uintN attrs);
+ 
+ /*
+  * Determine the attributes (JSPROP_* flags) of a property on a given object.
+  *
+  * If the object does not have a property by that name, *foundp will be
+  * JS_FALSE and the value of *attrsp is undefined.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+                          uintN *attrsp, JSBool *foundp);
+ 
+ /*
+  * The same, but if the property is native, return its getter and setter via
+  * *getterp and *setterp, respectively (and only if the out parameter pointer
+  * is not null).
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
+                                    const char *name,
+                                    uintN *attrsp, JSBool *foundp,
+                                    JSPropertyOp *getterp,
+                                    JSPropertyOp *setterp);
+ 
+ /*
+  * Set the attributes of a property on a given object.
+  *
+  * If the object does not have a property by that name, *foundp will be
+  * JS_FALSE and nothing will be altered.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+                          uintN attrs, JSBool *foundp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
+                             int8 tinyid, jsval value,
+                             JSPropertyOp getter, JSPropertyOp setter,
+                             uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
+                  const char *alias);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
+                            uintN flags, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
+              jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
+                    jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineUCProperty(JSContext *cx, JSObject *obj,
+                     const jschar *name, size_t namelen, jsval value,
+                     JSPropertyOp getter, JSPropertyOp setter,
+                     uintN attrs);
+ 
+ /*
+  * Determine the attributes (JSPROP_* flags) of a property on a given object.
+  *
+  * If the object does not have a property by that name, *foundp will be
+  * JS_FALSE and the value of *attrsp is undefined.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+                            const jschar *name, size_t namelen,
+                            uintN *attrsp, JSBool *foundp);
+ 
+ /*
+  * The same, but if the property is native, return its getter and setter via
+  * *getterp and *setterp, respectively (and only if the out parameter pointer
+  * is not null).
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
+                                      const jschar *name, size_t namelen,
+                                      uintN *attrsp, JSBool *foundp,
+                                      JSPropertyOp *getterp,
+                                      JSPropertyOp *setterp);
+ 
+ /*
+  * Set the attributes of a property on a given object.
+  *
+  * If the object does not have a property by that name, *foundp will be
+  * JS_FALSE and nothing will be altered.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+                            const jschar *name, size_t namelen,
+                            uintN attrs, JSBool *foundp);
+ 
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
+                               const jschar *name, size_t namelen,
+                               int8 tinyid, jsval value,
+                               JSPropertyOp getter, JSPropertyOp setter,
+                               uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_HasUCProperty(JSContext *cx, JSObject *obj,
+                  const jschar *name, size_t namelen,
+                  JSBool *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LookupUCProperty(JSContext *cx, JSObject *obj,
+                     const jschar *name, size_t namelen,
+                     jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetUCProperty(JSContext *cx, JSObject *obj,
+                  const jschar *name, size_t namelen,
+                  jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetUCProperty(JSContext *cx, JSObject *obj,
+                  const jschar *name, size_t namelen,
+                  jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
+                      const jschar *name, size_t namelen,
+                      jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IsArrayObject(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
+                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ClearScope(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSIdArray *)
+ JS_Enumerate(JSContext *cx, JSObject *obj);
+ 
+ /*
+  * Create an object to iterate over enumerable properties of obj, in arbitrary
+  * property definition order.  NB: This differs from longstanding for..in loop
+  * order, which uses order of property definition in obj.
+  */
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewPropertyIterator(JSContext *cx, JSObject *obj);
+ 
+ /*
+  * Return true on success with *idp containing the id of the next enumerable
+  * property to visit using iterobj, or JSVAL_VOID if there is no such property
+  * left to visit.  Return false on error.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+                jsval *vp, uintN *attrsp);
+ 
+ extern JS_PUBLIC_API(JSCheckAccessOp)
+ JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Security protocol.
+  */
+ struct JSPrincipals {
+     char *codebase;
+ 
+     /* XXX unspecified and unused by Mozilla code -- can we remove these? */
+     void * (* JS_DLL_CALLBACK getPrincipalArray)(JSContext *cx, JSPrincipals *);
+     JSBool (* JS_DLL_CALLBACK globalPrivilegesEnabled)(JSContext *cx, JSPrincipals *);
+ 
+     /* Don't call "destroy"; use reference counting macros below. */
+     jsrefcount refcount;
+ 
+     void   (* JS_DLL_CALLBACK destroy)(JSContext *cx, JSPrincipals *);
+     JSBool (* JS_DLL_CALLBACK subsume)(JSPrincipals *, JSPrincipals *);
+ };
+ 
+ #ifdef JS_THREADSAFE
+ #define JSPRINCIPALS_HOLD(cx, principals)   JS_HoldPrincipals(cx,principals)
+ #define JSPRINCIPALS_DROP(cx, principals)   JS_DropPrincipals(cx,principals)
+ 
+ extern JS_PUBLIC_API(jsrefcount)
+ JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals);
+ 
+ extern JS_PUBLIC_API(jsrefcount)
+ JS_DropPrincipals(JSContext *cx, JSPrincipals *principals);
+ 
+ #else
+ #define JSPRINCIPALS_HOLD(cx, principals)   (++(principals)->refcount)
+ #define JSPRINCIPALS_DROP(cx, principals)                                     \
+     ((--(principals)->refcount == 0)                                          \
+      ? ((*(principals)->destroy)((cx), (principals)), 0)                      \
+      : (principals)->refcount)
+ #endif
+ 
+ extern JS_PUBLIC_API(JSPrincipalsTranscoder)
+ JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px);
+ 
+ extern JS_PUBLIC_API(JSObjectPrincipalsFinder)
+ JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Functions and scripts.
+  */
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags,
+                JSObject *parent, const char *name);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetFunctionObject(JSFunction *fun);
+ 
+ /*
+  * Deprecated, useful only for diagnostics.  Use JS_GetFunctionId instead for
+  * anonymous vs. "anonymous" disambiguation and Unicode fidelity.
+  */
+ extern JS_PUBLIC_API(const char *)
+ JS_GetFunctionName(JSFunction *fun);
+ 
+ /*
+  * Return the function's identifier as a JSString, or null if fun is unnamed.
+  * The returned string lives as long as fun, so you don't need to root a saved
+  * reference to it if fun is well-connected or rooted, and provided you bound
+  * the use of the saved reference by fun's lifetime.
+  *
+  * Prefer JS_GetFunctionId over JS_GetFunctionName because it returns null for
+  * truly anonymous functions, and because it doesn't chop to ISO-Latin-1 chars
+  * from UTF-16-ish jschars.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_GetFunctionId(JSFunction *fun);
+ 
+ /*
+  * Return JSFUN_* flags for fun.
+  */
+ extern JS_PUBLIC_API(uintN)
+ JS_GetFunctionFlags(JSFunction *fun);
+ 
+ /*
+  * Infallible predicate to test whether obj is a function object (faster than
+  * comparing obj's class name to "Function", but equivalent unless someone has
+  * overwritten the "Function" identifier with a different constructor and then
+  * created instances using that constructor that might be passed in as obj).
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ObjectIsFunction(JSContext *cx, JSObject *obj);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+                   uintN nargs, uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_DefineUCFunction(JSContext *cx, JSObject *obj,
+                     const jschar *name, size_t namelen, JSNative call,
+                     uintN nargs, uintN attrs);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
+ 
+ /*
+  * Given a buffer, return JS_FALSE if the buffer might become a valid
+  * javascript statement with the addition of more lines.  Otherwise return
+  * JS_TRUE.  The intent is to support interactive compilation - accumulate
+  * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to
+  * the compiler.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
+                           const char *bytes, size_t length);
+ 
+ /*
+  * The JSScript objects returned by the following functions refer to string and
+  * other kinds of literals, including doubles and RegExp objects.  These
+  * literals are vulnerable to garbage collection; to root script objects and
+  * prevent literals from being collected, create a rootable object using
+  * JS_NewScriptObject, and root the resulting object using JS_Add[Named]Root.
+  */
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileScript(JSContext *cx, JSObject *obj,
+                  const char *bytes, size_t length,
+                  const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
+                               JSPrincipals *principals,
+                               const char *bytes, size_t length,
+                               const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileUCScript(JSContext *cx, JSObject *obj,
+                    const jschar *chars, size_t length,
+                    const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+                                 JSPrincipals *principals,
+                                 const jschar *chars, size_t length,
+                                 const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
+                      FILE *fh);
+ 
+ extern JS_PUBLIC_API(JSScript *)
+ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
+                                   const char *filename, FILE *fh,
+                                   JSPrincipals *principals);
+ 
+ /*
+  * NB: you must use JS_NewScriptObject and root a pointer to its return value
+  * in order to keep a JSScript and its atoms safe from garbage collection after
+  * creating the script via JS_Compile* and before a JS_ExecuteScript* call.
+  * E.g., and without error checks:
+  *
+  *    JSScript *script = JS_CompileFile(cx, global, filename);
+  *    JSObject *scrobj = JS_NewScriptObject(cx, script);
+  *    JS_AddNamedRoot(cx, &scrobj, "scrobj");
+  *    do {
+  *        jsval result;
+  *        JS_ExecuteScript(cx, global, script, &result);
+  *        JS_GC();
+  *    } while (!JSVAL_IS_BOOLEAN(result) || JSVAL_TO_BOOLEAN(result));
+  *    JS_RemoveRoot(cx, &scrobj);
+  */
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewScriptObject(JSContext *cx, JSScript *script);
+ 
+ /*
+  * Infallible getter for a script's object.  If JS_NewScriptObject has not been
+  * called on script yet, the return value will be null.
+  */
+ extern JS_PUBLIC_API(JSObject *)
+ JS_GetScriptObject(JSScript *script);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DestroyScript(JSContext *cx, JSScript *script);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
+                    uintN nargs, const char **argnames,
+                    const char *bytes, size_t length,
+                    const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
+                                 JSPrincipals *principals, const char *name,
+                                 uintN nargs, const char **argnames,
+                                 const char *bytes, size_t length,
+                                 const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
+                      uintN nargs, const char **argnames,
+                      const jschar *chars, size_t length,
+                      const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSFunction *)
+ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
+                                   JSPrincipals *principals, const char *name,
+                                   uintN nargs, const char **argnames,
+                                   const jschar *chars, size_t length,
+                                   const char *filename, uintN lineno);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
+                    uintN indent);
+ 
+ /*
+  * API extension: OR this into indent to avoid pretty-printing the decompiled
+  * source resulting from JS_DecompileFunction{,Body}.
+  */
+ #define JS_DONT_PRETTY_PRINT    ((uintN)0x8000)
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent);
+ 
+ /*
+  * NB: JS_ExecuteScript, JS_ExecuteScriptPart, and the JS_Evaluate*Script*
+  * quadruplets all use the obj parameter as the initial scope chain header,
+  * the 'this' keyword value, and the variables object (ECMA parlance for where
+  * 'var' and 'function' bind names) of the execution context for script.
+  *
+  * Using obj as the variables object is problematic if obj's parent (which is
+  * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in
+  * this case, variables created by 'var x = 0', e.g., go in obj, but variables
+  * created by assignment to an unbound id, 'x = 0', go in the last object on
+  * the scope chain linked by parent.
+  *
+  * ECMA calls that last scoping object the "global object", but note that many
+  * embeddings have several such objects.  ECMA requires that "global code" be
+  * executed with the variables object equal to this global object.  But these
+  * JS API entry points provide freedom to execute code against a "sub-global",
+  * i.e., a parented or scoped object, in which case the variables object will
+  * differ from the last object on the scope chain, resulting in confusing and
+  * non-ECMA explicit vs. implicit variable creation.
+  *
+  * Caveat embedders: unless you already depend on this buggy variables object
+  * binding behavior, you should call JS_SetOptions(cx, JSOPTION_VAROBJFIX) or
+  * JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX) -- the latter if
+  * someone may have set other options on cx already -- for each context in the
+  * application, if you pass parented objects as the obj parameter, or may ever
+  * pass such objects in the future.
+  *
+  * Why a runtime option?  The alternative is to add six or so new API entry
+  * points with signatures matching the following six, and that doesn't seem
+  * worth the code bloat cost.  Such new entry points would probably have less
+  * obvious names, too, so would not tend to be used.  The JS_SetOption call,
+  * OTOH, can be more easily hacked into existing code that does not depend on
+  * the bug; such code can continue to use the familiar JS_EvaluateScript,
+  * etc., entry points.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval);
+ 
+ /*
+  * Execute either the function-defining prolog of a script, or the script's
+  * main body, but not both.
+  */
+ typedef enum JSExecPart { JSEXEC_PROLOG, JSEXEC_MAIN } JSExecPart;
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
+                      JSExecPart part, jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EvaluateScript(JSContext *cx, JSObject *obj,
+                   const char *bytes, uintN length,
+                   const char *filename, uintN lineno,
+                   jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
+                                JSPrincipals *principals,
+                                const char *bytes, uintN length,
+                                const char *filename, uintN lineno,
+                                jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
+                     const jschar *chars, uintN length,
+                     const char *filename, uintN lineno,
+                     jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+                                  JSPrincipals *principals,
+                                  const jschar *chars, uintN length,
+                                  const char *filename, uintN lineno,
+                                  jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
+                 jsval *argv, jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
+                     jsval *argv, jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
+                      jsval *argv, jsval *rval);
+ 
+ extern JS_PUBLIC_API(JSBranchCallback)
+ JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IsRunning(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IsConstructing(JSContext *cx);
+ 
+ /*
+  * Returns true if a script is executing and its current bytecode is a set
+  * (assignment) operation, even if there are native (no script) stack frames
+  * between the script and the caller to JS_IsAssigning.
+  */
+ extern JS_FRIEND_API(JSBool)
+ JS_IsAssigning(JSContext *cx);
+ 
+ /*
+  * Set the second return value, which should be a string or int jsval that
+  * identifies a property in the returned object, to form an ECMA reference
+  * type value (obj, id).  Only native methods can return reference types,
+  * and if the returned value is used on the left-hand side of an assignment
+  * op, the identified property will be set.  If the return value is in an
+  * r-value, the interpreter just gets obj[id]'s value.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_SetCallReturnValue2(JSContext *cx, jsval v);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Strings.
+  *
+  * NB: JS_NewString takes ownership of bytes on success, avoiding a copy; but
+  * on error (signified by null return), it leaves bytes owned by the caller.
+  * So the caller must free bytes in the error case, if it has no use for them.
+  * In contrast, all the JS_New*StringCopy* functions do not take ownership of
+  * the character memory passed to them -- they copy it.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewString(JSContext *cx, char *bytes, size_t length);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewStringCopyZ(JSContext *cx, const char *s);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_InternString(JSContext *cx, const char *s);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewUCString(JSContext *cx, jschar *chars, size_t length);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewUCStringCopyZ(JSContext *cx, const jschar *s);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length);
+ 
+ extern JS_PUBLIC_API(JSString *)
+ JS_InternUCString(JSContext *cx, const jschar *s);
+ 
+ extern JS_PUBLIC_API(char *)
+ JS_GetStringBytes(JSString *str);
+ 
+ extern JS_PUBLIC_API(jschar *)
+ JS_GetStringChars(JSString *str);
+ 
+ extern JS_PUBLIC_API(size_t)
+ JS_GetStringLength(JSString *str);
+ 
+ extern JS_PUBLIC_API(intN)
+ JS_CompareStrings(JSString *str1, JSString *str2);
+ 
+ /*
+  * Mutable string support.  A string's characters are never mutable in this JS
+  * implementation, but a growable string has a buffer that can be reallocated,
+  * and a dependent string is a substring of another (growable, dependent, or
+  * immutable) string.  The direct data members of the (opaque to API clients)
+  * JSString struct may be changed in a single-threaded way for growable and
+  * dependent strings.
+  *
+  * Therefore mutable strings cannot be used by more than one thread at a time.
+  * You may call JS_MakeStringImmutable to convert the string from a mutable
+  * (growable or dependent) string to an immutable (and therefore thread-safe)
+  * string.  The engine takes care of converting growable and dependent strings
+  * to immutable for you if you store strings in multi-threaded objects using
+  * JS_SetProperty or kindred API entry points.
+  *
+  * If you store a JSString pointer in a native data structure that is (safely)
+  * accessible to multiple threads, you must call JS_MakeStringImmutable before
+  * retiring the store.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length);
+ 
+ /*
+  * Create a dependent string, i.e., a string that owns no character storage,
+  * but that refers to a slice of another string's chars.  Dependent strings
+  * are mutable by definition, so the thread safety comments above apply.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
+                       size_t length);
+ 
+ /*
+  * Concatenate two strings, resulting in a new growable string.  If you create
+  * the left string and pass it to JS_ConcatStrings on a single thread, try to
+  * use JS_NewGrowableString to create the left string -- doing so helps Concat
+  * avoid allocating a new buffer for the result and copying left's chars into
+  * the new buffer.  See above for thread safety comments.
+  */
+ extern JS_PUBLIC_API(JSString *)
+ JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
+ 
+ /*
+  * Convert a dependent string into an independent one.  This function does not
+  * change the string's mutability, so the thread safety comments above apply.
+  */
+ extern JS_PUBLIC_API(const jschar *)
+ JS_UndependString(JSContext *cx, JSString *str);
+ 
+ /*
+  * Convert a mutable string (either growable or dependent) into an immutable,
+  * thread-safe one.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_MakeStringImmutable(JSContext *cx, JSString *str);
+ 
+ /*
+  * Return JS_TRUE if C (char []) strings passed via the API and internally
+  * are UTF-8. The source must be compiled with JS_C_STRINGS_ARE_UTF8 defined
+  * to get UTF-8 support.
+  */
+ JS_PUBLIC_API(JSBool)
+ JS_CStringsAreUTF8();
+ 
+ /*
+  * Character encoding support.
+  *
+  * For both JS_EncodeCharacters and JS_DecodeBytes, set *dstlenp to the size
+  * of the destination buffer before the call; on return, *dstlenp contains the
+  * number of bytes (JS_EncodeCharacters) or jschars (JS_DecodeBytes) actually
+  * stored.  To determine the necessary destination buffer size, make a sizing
+  * call that passes NULL for dst.
+  *
+  * On errors, the functions report the error. In that case, *dstlenp contains
+  * the number of characters or bytes transferred so far.  If cx is NULL, no
+  * error is reported on failure, and the functions simply return JS_FALSE.
+  *
+  * NB: Neither function stores an additional zero byte or jschar after the
+  * transcoded string.
+  *
+  * If the source has been compiled with the #define JS_C_STRINGS_ARE_UTF8 to
+  * enable UTF-8 interpretation of C char[] strings, then JS_EncodeCharacters
+  * encodes to UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create
+  * addititional errors if the character sequence is malformed.  If UTF-8
+  * support is disabled, the functions deflate and inflate, respectively.
+  */
+ JS_PUBLIC_API(JSBool)
+ JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
+                     size_t *dstlenp);
+ 
+ JS_PUBLIC_API(JSBool)
+ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
+                size_t *dstlenp);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Locale specific string conversion and error message callbacks.
+  */
+ struct JSLocaleCallbacks {
+     JSLocaleToUpperCase     localeToUpperCase;
+     JSLocaleToLowerCase     localeToLowerCase;
+     JSLocaleCompare         localeCompare;
+     JSLocaleToUnicode       localeToUnicode;
+     JSErrorCallback         localeGetErrorMessage;
+ };
+ 
+ /*
+  * Establish locale callbacks. The pointer must persist as long as the
+  * JSContext.  Passing NULL restores the default behaviour.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks);
+ 
+ /*
+  * Return the address of the current locale callbacks struct, which may
+  * be NULL.
+  */
+ extern JS_PUBLIC_API(JSLocaleCallbacks *)
+ JS_GetLocaleCallbacks(JSContext *cx);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Error reporting.
+  */
+ 
+ /*
+  * Report an exception represented by the sprintf-like conversion of format
+  * and its arguments.  This exception message string is passed to a pre-set
+  * JSErrorReporter function (set by JS_SetErrorReporter; see jspubtd.h for
+  * the JSErrorReporter typedef).
+  */
+ extern JS_PUBLIC_API(void)
+ JS_ReportError(JSContext *cx, const char *format, ...);
+ 
+ /*
+  * Use an errorNumber to retrieve the format string, args are char *
+  */
+ extern JS_PUBLIC_API(void)
+ JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
+                      void *userRef, const uintN errorNumber, ...);
+ 
+ /*
+  * Use an errorNumber to retrieve the format string, args are jschar *
+  */
+ extern JS_PUBLIC_API(void)
+ JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
+                      void *userRef, const uintN errorNumber, ...);
+ 
+ /*
+  * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)).
+  * Return true if there was no error trying to issue the warning, and if the
+  * warning was not converted into an error due to the JSOPTION_WERROR option
+  * being set, false otherwise.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ReportWarning(JSContext *cx, const char *format, ...);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
+                              JSErrorCallback errorCallback, void *userRef,
+                              const uintN errorNumber, ...);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
+                                JSErrorCallback errorCallback, void *userRef,
+                                const uintN errorNumber, ...);
+ 
+ /*
+  * Complain when out of memory.
+  */
+ extern JS_PUBLIC_API(void)
+ JS_ReportOutOfMemory(JSContext *cx);
+ 
+ struct JSErrorReport {
+     const char      *filename;      /* source file name, URL, etc., or null */
+     uintN           lineno;         /* source line number */
+     const char      *linebuf;       /* offending source line without final \n */
+     const char      *tokenptr;      /* pointer to error token in linebuf */
+     const jschar    *uclinebuf;     /* unicode (original) line buffer */
+     const jschar    *uctokenptr;    /* unicode (original) token pointer */
+     uintN           flags;          /* error/warning, etc. */
+     uintN           errorNumber;    /* the error number, e.g. see js.msg */
+     const jschar    *ucmessage;     /* the (default) error message */
+     const jschar    **messageArgs;  /* arguments for the error message */
+ };
+ 
+ /*
+  * JSErrorReport flag values.  These may be freely composed.
+  */
+ #define JSREPORT_ERROR      0x0     /* pseudo-flag for default case */
+ #define JSREPORT_WARNING    0x1     /* reported via JS_ReportWarning */
+ #define JSREPORT_EXCEPTION  0x2     /* exception was thrown */
+ #define JSREPORT_STRICT     0x4     /* error or warning due to strict option */
+ 
+ /*
+  * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception
+  * has been thrown for this runtime error, and the host should ignore it.
+  * Exception-aware hosts should also check for JS_IsExceptionPending if
+  * JS_ExecuteScript returns failure, and signal or propagate the exception, as
+  * appropriate.
+  */
+ #define JSREPORT_IS_WARNING(flags)      (((flags) & JSREPORT_WARNING) != 0)
+ #define JSREPORT_IS_EXCEPTION(flags)    (((flags) & JSREPORT_EXCEPTION) != 0)
+ #define JSREPORT_IS_STRICT(flags)       (((flags) & JSREPORT_STRICT) != 0)
+ 
+ extern JS_PUBLIC_API(JSErrorReporter)
+ JS_SetErrorReporter(JSContext *cx, JSErrorReporter er);
+ 
+ /************************************************************************/
+ 
+ /*
+  * Regular Expressions.
+  */
+ #define JSREG_FOLD      0x01    /* fold uppercase to lowercase */
+ #define JSREG_GLOB      0x02    /* global exec, creates array of matches */
+ #define JSREG_MULTILINE 0x04    /* treat ^ and $ as begin and end of line */
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags);
+ 
+ extern JS_PUBLIC_API(JSObject *)
+ JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ClearRegExpStatics(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ClearRegExpRoots(JSContext *cx);
+ 
+ /* TODO: compile, exec, get/set other statics... */
+ 
+ /************************************************************************/
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_IsExceptionPending(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_GetPendingException(JSContext *cx, jsval *vp);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_SetPendingException(JSContext *cx, jsval v);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_ClearPendingException(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(JSBool)
+ JS_ReportPendingException(JSContext *cx);
+ 
+ /*
+  * Save the current exception state.  This takes a snapshot of cx's current
+  * exception state without making any change to that state.
+  *
+  * The returned state pointer MUST be passed later to JS_RestoreExceptionState
+  * (to restore that saved state, overriding any more recent state) or else to
+  * JS_DropExceptionState (to free the state struct in case it is not correct
+  * or desirable to restore it).  Both Restore and Drop free the state struct,
+  * so callers must stop using the pointer returned from Save after calling the
+  * Release or Drop API.
+  */
+ extern JS_PUBLIC_API(JSExceptionState *)
+ JS_SaveExceptionState(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state);
+ 
+ extern JS_PUBLIC_API(void)
+ JS_DropExceptionState(JSContext *cx, JSExceptionState *state);
+ 
+ /*
+  * If the given value is an exception object that originated from an error,
+  * the exception will contain an error report struct, and this API will return
+  * the address of that struct.  Otherwise, it returns NULL.  The lifetime of
+  * the error report struct that might be returned is the same as the lifetime
+  * of the exception object.
+  */
+ extern JS_PUBLIC_API(JSErrorReport *)
+ JS_ErrorFromException(JSContext *cx, jsval v);
+ 
+ /*
+  * Given a reported error's message and JSErrorReport struct pointer, throw
+  * the corresponding exception on cx.
+  */
+ extern JS_PUBLIC_API(JSBool)
+ JS_ThrowReportedError(JSContext *cx, const char *message,
+                       JSErrorReport *reportp);
+ 
+ #ifdef JS_THREADSAFE
+ 
+ /*
+  * Associate the current thread with the given context.  This is done
+  * implicitly by JS_NewContext.
+  *
+  * Returns the old thread id for this context, which should be treated as
+  * an opaque value.  This value is provided for comparison to 0, which
+  * indicates that ClearContextThread has been called on this context
+  * since the last SetContextThread, or non-0, which indicates the opposite.
+  */
+ extern JS_PUBLIC_API(jsword)
+ JS_GetContextThread(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsword)
+ JS_SetContextThread(JSContext *cx);
+ 
+ extern JS_PUBLIC_API(jsword)
+ JS_ClearContextThread(JSContext *cx);
+ 
+ #endif /* JS_THREADSAFE */
+ 
+ /************************************************************************/
+ 
+ JS_END_EXTERN_C
+ 
+ #endif /* jsapi_h___ */


ossp-pkg/js/src/jsatom.c 1.1.1.1 -> 1.1.1.2

--- jsatom.c     2005/08/22 17:36:57     1.1.1.1
+++ jsatom.c     2006/04/04 14:09:45     1.1.1.2
@@ -719,12 +719,15 @@
      */
 #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;
@@ -733,7 +736,7 @@
     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);


ossp-pkg/js/src/jscntxt.c 1.1.1.1 -> 1.1.1.2

--- jscntxt.c    2005/11/01 00:47:49     1.1.1.1
+++ jscntxt.c    2006/04/04 14:09:45     1.1.1.2
@@ -1,4 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@@ -712,14 +713,15 @@
  * type message, and then hope the process ends swiftly.
  */
 void
-js_ReportOutOfMemory(JSContext *cx, JSErrorCallback callback)
+js_ReportOutOfMemory(JSContext *cx)
 {
     JSStackFrame *fp;
     JSErrorReport report;
     JSErrorReporter onError = cx->errorReporter;
 
     /* Get the message for this error, but we won't expand any arguments. */
-    const JSErrorFormatString *efs = callback(NULL, NULL, JSMSG_OUT_OF_MEMORY);
+    const JSErrorFormatString *efs = 
+        js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
     const char *msg = efs ? efs->format : "Out of memory";
 
     /* Fill out the report, but don't do anything that requires allocation. */
@@ -821,104 +823,112 @@
     }
 
     *messagep = NULL;
-    if (callback) {
+
+    /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
+    if (!callback || callback == js_GetErrorMessage)
+        efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber);
+    else
         efs = callback(userRef, NULL, errorNumber);
-        if (efs) {
-            size_t totalArgsLength = 0;
-            size_t argLengths[10]; /* only {0} thru {9} supported */
-            argCount = efs->argCount;
-            JS_ASSERT(argCount <= 10);
-            if (argCount > 0) {
-                /*
-                 * Gather the arguments into an array, and accumulate
-                 * their sizes. We allocate 1 more than necessary and
-                 * null it out to act as the caboose when we free the
-                 * pointers later.
-                 */
-                reportp->messageArgs = (const jschar **)
-                    JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
-                if (!reportp->messageArgs)
-                    return JS_FALSE;
-                reportp->messageArgs[argCount] = NULL;
-                for (i = 0; i < argCount; i++) {
-                    if (charArgs) {
-                        char *charArg = va_arg(ap, char *);
-                        reportp->messageArgs[i]
-                            = js_InflateString(cx, charArg, strlen(charArg));
-                        if (!reportp->messageArgs[i])
-                            goto error;
-                    }
-                    else
-                        reportp->messageArgs[i] = va_arg(ap, jschar *);
-                    argLengths[i] = js_strlen(reportp->messageArgs[i]);
-                    totalArgsLength += argLengths[i];
-                }
-                /* NULL-terminate for easy copying. */
-                reportp->messageArgs[i] = NULL;
-            }
+    if (efs) {
+        size_t totalArgsLength = 0;
+        size_t argLengths[10]; /* only {0} thru {9} supported */
+        argCount = efs->argCount;
+        JS_ASSERT(argCount <= 10);
+        if (argCount > 0) {
             /*
-             * Parse the error format, substituting the argument X
-             * for {X} in the format.
+             * Gather the arguments into an array, and accumulate
+             * their sizes. We allocate 1 more than necessary and
+             * null it out to act as the caboose when we free the
+             * pointers later.
              */
-            if (argCount > 0) {
-                if (efs->format) {
-                    const char *fmt;
-                    const jschar *arg;
-                    jschar *out;
-                    int expandedArgs = 0;
-                    size_t expandedLength
-                        = strlen(efs->format)
-                            - (3 * argCount) /* exclude the {n} */
-                            + totalArgsLength;
-                    /*
-                     * Note - the above calculation assumes that each argument
-                     * is used once and only once in the expansion !!!
-                     */
-                    reportp->ucmessage = out = (jschar *)
-                        JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
-                    if (!out)
-                        goto error;
-                    fmt = efs->format;
-                    while (*fmt) {
-                        if (*fmt == '{') {
-                            if (isdigit(fmt[1])) {
-                                int d = JS7_UNDEC(fmt[1]);
-                                JS_ASSERT(d < argCount);
-                                arg = reportp->messageArgs[d];
-                                js_strncpy(out, arg, argLengths[d]);
-                                out += argLengths[d];
-                                fmt += 3;
-                                expandedArgs++;
-                                continue;
-                            }
-                        }
-                        /*
-                         * is this kosher?
-                         */
-                        *out++ = (unsigned char)(*fmt++);
-                    }
-                    JS_ASSERT(expandedArgs == argCount);
-                    *out = 0;
-                    *messagep =
-                        js_DeflateString(cx, reportp->ucmessage,
-                                         (size_t)(out - reportp->ucmessage));
-                    if (!*messagep)
+            reportp->messageArgs = (const jschar **)
+                JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
+            if (!reportp->messageArgs)
+                return JS_FALSE;
+            reportp->messageArgs[argCount] = NULL;
+            for (i = 0; i < argCount; i++) {
+                if (charArgs) {
+                    char *charArg = va_arg(ap, char *);
+                    size_t charArgLength = strlen(charArg);
+                    reportp->messageArgs[i]
+                        = js_InflateString(cx, charArg, &charArgLength);
+                    if (!reportp->messageArgs[i])
                         goto error;
+                } else {
+                    reportp->messageArgs[i] = va_arg(ap, jschar *);
                 }
-            } else {
+                argLengths[i] = js_strlen(reportp->messageArgs[i]);
+                totalArgsLength += argLengths[i];
+            }
+            /* NULL-terminate for easy copying. */
+            reportp->messageArgs[i] = NULL;
+        }
+        /*
+         * Parse the error format, substituting the argument X
+         * for {X} in the format.
+         */
+        if (argCount > 0) {
+            if (efs->format) {
+                jschar *buffer, *fmt, *out;
+                int expandedArgs = 0;
+                size_t expandedLength;
+                size_t len = strlen(efs->format);
+
+                buffer = fmt = js_InflateString (cx, efs->format, &len);
+                if (!buffer)
+                    goto error;
+                expandedLength = len
+                                 - (3 * argCount)       /* exclude the {n} */
+                                 + totalArgsLength;
+
                 /*
-                 * Zero arguments: the format string (if it exists) is the
-                 * entire message.
-                 */
-                if (efs->format) {
-                    *messagep = JS_strdup(cx, efs->format);
-                    if (!*messagep)
-                        goto error;
-                    reportp->ucmessage
-                        = js_InflateString(cx, *messagep, strlen(*messagep));
-                    if (!reportp->ucmessage)
-                        goto error;
+                * Note - the above calculation assumes that each argument
+                * is used once and only once in the expansion !!!
+                */
+                reportp->ucmessage = out = (jschar *)
+                    JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
+                if (!out) {
+                    JS_free (cx, buffer);
+                    goto error;
+                }
+                while (*fmt) {
+                    if (*fmt == '{') {
+                        if (isdigit(fmt[1])) {
+                            int d = JS7_UNDEC(fmt[1]);
+                            JS_ASSERT(d < argCount);
+                            js_strncpy(out, reportp->messageArgs[d],
+                                       argLengths[d]);
+                            out += argLengths[d];
+                            fmt += 3;
+                            expandedArgs++;
+                            continue;
+                        }
+                    }
+                    *out++ = *fmt++;
                 }
+                JS_ASSERT(expandedArgs == argCount);
+                *out = 0;
+                JS_free (cx, buffer);
+                *messagep =
+                    js_DeflateString(cx, reportp->ucmessage,
+                                     (size_t)(out - reportp->ucmessage));
+                if (!*messagep)
+                    goto error;
+            }
+        } else {
+            /*
+             * Zero arguments: the format string (if it exists) is the
+             * entire message.
+             */
+            if (efs->format) {
+                size_t len;
+                *messagep = JS_strdup(cx, efs->format);
+                if (!*messagep)
+                    goto error;
+                len = strlen(*messagep);
+                reportp->ucmessage = js_InflateString(cx, *messagep, &len);
+                if (!reportp->ucmessage)
+                    goto error;
             }
         }
     }
@@ -992,9 +1002,15 @@
     if (message)
         JS_free(cx, message);
     if (report.messageArgs) {
-        int i = 0;
-        while (report.messageArgs[i])
-            JS_free(cx, (void *)report.messageArgs[i++]);
+        /*
+         * js_ExpandErrorArguments owns its messageArgs only if it had to
+         * inflate the arguments (from regular |char *|s).
+         */
+        if (charArgs) {
+            int i = 0;
+            while (report.messageArgs[i])
+                JS_free(cx, (void *)report.messageArgs[i++]);
+        }
         JS_free(cx, (void *)report.messageArgs);
     }
     if (report.ucmessage)
@@ -1049,10 +1065,10 @@
 JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
 #if JS_HAS_DFLT_MSG_STRINGS
 #define MSG_DEF(name, number, count, exception, format) \
-    { format, count } ,
+    { format, count, exception } ,
 #else
 #define MSG_DEF(name, number, count, exception, format) \
-    { NULL, count } ,
+    { NULL, count, exception } ,
 #endif
 #include "js.msg"
 #undef MSG_DEF


ossp-pkg/js/src/jsinterp.c 1.1.1.1 -> 1.1.1.2

--- jsinterp.c   2006/06/16 01:28:02     1.1.1.1
+++ jsinterp.c   2006/04/04 14:09:45     1.1.1.2
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=80:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@@ -460,6 +460,8 @@
 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);
@@ -488,26 +490,13 @@
          */
         JS_ASSERT(!(fp->flags & JSFRAME_CONSTRUCTING));
         if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||
-            !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2]))) {
+            !(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {
             thisp = cx->globalObject;
         } else {
-            jsid id;
-            jsval v;
-            uintN attrs;
-
-            /* Walk up the parent chain. */
-            thisp = JSVAL_TO_OBJECT(fp->argv[-2]);
-            id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
-            for (;;) {
-                if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs))
-                    return JS_FALSE;
-                if (JSVAL_IS_VOID(v))
-                    v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT);
-                JS_ASSERT(JSVAL_TO_OBJECT(v) == OBJ_GET_PARENT(cx, thisp));
-                if (JSVAL_IS_NULL(v))
-                    break;
-                thisp = JSVAL_TO_OBJECT(v);
-            }
+            /* walk up to find the top-level object */
+            thisp = parent;
+            while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)
+                thisp = parent;
         }
     }
     fp->thisp = thisp;
@@ -1993,17 +1982,6 @@
                         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);
@@ -2280,23 +2258,12 @@
 
             /* Is this the first iteration ? */
             if (JSVAL_IS_VOID(rval)) {
-                /*
-                 * Yes, create a new JSObject to hold the iterator state.
-                 * Use NULL as the nominal parent in js_NewObject to ensure
-                 * that we use the correct scope chain lookup to try to find the
-                 * PropertyIterator constructor.
-                 */
-                propobj = js_NewObject(cx, &prop_iterator_class, NULL, NULL);
+                /* Yes, create a new JSObject to hold the iterator state */
+                propobj = js_NewObject(cx, &prop_iterator_class, NULL, obj);
                 if (!propobj) {
                     ok = JS_FALSE;
                     goto out;
                 }
-
-                /*
-                 * 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;
 
                 /*
@@ -3394,12 +3361,17 @@
 #undef FAST_GLOBAL_INCREMENT_OP
 
           do_nonint_fast_global_incop:
+          {
+            const JSCodeSpec *cs = &js_CodeSpec[op];
+
             vp = sp++;
             SAVE_SP(fp);
             NONINT_INCREMENT_OP_MIDDLE();
             OBJ_SET_SLOT(cx, obj, slot, rval);
             STORE_OPND(-1, rtmp);
+            len = cs->length;
             break;
+          }
 
           case JSOP_GETPROP:
             /* Get an immediate atom naming the property. */
@@ -4556,7 +4528,8 @@
              */
             SAVE_SP(fp);
             obj2 = fp->scopeChain;
-            parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2);
+            parent = js_ConstructObject(cx, &js_ObjectClass, NULL, obj2,
+                                        0, NULL);
             if (!parent) {
                 ok = JS_FALSE;
                 goto out;
@@ -4982,24 +4955,12 @@
             JS_ASSERT(JSVAL_IS_OBJECT(lval));
             obj = JSVAL_TO_OBJECT(lval);
 
+            /* Define obj[id] to contain rval and to be permanent. */
             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);
+            ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
+                                     JSPROP_PERMANENT, NULL);
             if (!ok)
                 goto out;
-            if (!(attrs & (JSPROP_READONLY | JSPROP_PERMANENT |
-                           JSPROP_GETTER | JSPROP_SETTER))) {
-                /* Define obj[id] to contain rval and to be permanent. */
-                ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
-                                         JSPROP_PERMANENT, NULL);
-                if (!ok)
-                    goto out;
-            }
 
             /* Now that we're done with rval, pop it. */
             sp--;


ossp-pkg/js/src/jsprf.c 1.1.1.1 -> 1.1.1.2

--- jsprf.c      2004/09/24 03:31:15     1.1.1.1
+++ jsprf.c      2006/04/04 14:09:45     1.1.1.2
@@ -49,6 +49,8 @@
 #include "jsprf.h"
 #include "jslong.h"
 #include "jsutil.h" /* Added by JSIFY */
+#include "jspubtd.h"
+#include "jsstr.h"
 
 /*
 ** Note: on some platforms va_list is defined as an array,
@@ -105,6 +107,7 @@
 #define TYPE_STRING     8
 #define TYPE_DOUBLE     9
 #define TYPE_INTSTR     10
+#define TYPE_WSTRING    11
 #define TYPE_UNKNOWN    20
 
 #define FLAG_LEFT       0x1
@@ -395,6 +398,27 @@
     return fill2(ss, s ? s : "(null)", slen, width, flags);
 }
 
+static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
+                  int flags)
+{
+    int result;
+    /* 
+     * Supply NULL as the JSContext; errors are not reported, 
+     * and malloc() is used to allocate the buffer buffer. 
+     */
+    if (ws) {
+        int slen = js_strlen(ws);
+        char *s = js_DeflateString(NULL, ws, slen);
+        if (!s)
+            return -1; /* JSStuffFunc error indicator. */
+        result = cvt_s(ss, s, width, prec, flags);
+        free(s);
+    } else {
+        result = cvt_s(ss, NULL, width, prec, flags);
+    }
+    return result;
+}
+
 /*
 ** BuildArgArray stands for Numbered Argument list Sprintf
 ** for example,
@@ -578,7 +602,7 @@
             break;
 
         case 's':
-            nas[ cn ].type = TYPE_STRING;
+            nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
             break;
 
         case 'n':
@@ -635,6 +659,8 @@
 
         case TYPE_STRING:       (void)va_arg( ap, char* );              break;
 
+        case TYPE_WSTRING:      (void)va_arg( ap, jschar* );            break;
+
         case TYPE_INTSTR:       (void)va_arg( ap, JSIntn* );            break;
 
         case TYPE_DOUBLE:       (void)va_arg( ap, double );             break;
@@ -662,11 +688,13 @@
     int flags, width, prec, radix, type;
     union {
         char ch;
+        jschar wch;
         int i;
         long l;
         JSInt64 ll;
         double d;
         const char *s;
+        const jschar* ws;
         int *ip;
     } u;
     const char *fmt0;
@@ -678,7 +706,10 @@
     struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
     char pattern[20];
     const char *dolPt = NULL;  /* in "%4$.2f", dolPt will poiont to . */
-
+#ifdef JS_C_STRINGS_ARE_UTF8
+    char utf8buf[6];
+    int utf8len;
+#endif
 
     /*
     ** build an argument array, IF the fmt is numbered argument
@@ -905,7 +936,6 @@
             break;
 
           case 'c':
-            u.ch = va_arg(ap, int);
             if ((flags & FLAG_LEFT) == 0) {
                 while (width-- > 1) {
                     rv = (*ss->stuff)(ss, " ", 1);
@@ -914,7 +944,20 @@
                     }
                 }
             }
-            rv = (*ss->stuff)(ss, &u.ch, 1);
+            switch (type) {
+              case TYPE_INT16:
+                /* Treat %hc as %c if JS_C_STRINGS_ARE_UTF8 is undefined. */
+#ifdef JS_C_STRINGS_ARE_UTF8
+                u.wch = va_arg(ap, int);
+                utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
+                rv = (*ss->stuff)(ss, utf8buf, utf8len);
+                break;
+#endif
+              case TYPE_INTN:
+                u.ch = va_arg(ap, int);
+                rv = (*ss->stuff)(ss, &u.ch, 1);
+                break;
+            }
             if (rv < 0) {
                 return rv;
             }
@@ -953,8 +996,17 @@
 #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;
             }


ossp-pkg/js/src/jspubtd.h 1.1.1.1 -> 1.1.1.2

--- jspubtd.h    2005/10/21 23:30:23     1.1.1.1
+++ jspubtd.h    2006/04/04 14:09:45     1.1.1.2
@@ -546,9 +546,28 @@
 (* JS_DLL_CALLBACK JSErrorReporter)(JSContext *cx, const char *message,
                                     JSErrorReport *report);
 
+/*
+ * Possible exception types. These types are part of a JSErrorFormatString 
+ * structure. They define which error to throw in case of a runtime error.
+ * JSEXN_NONE marks an unthrowable error.
+ */
+typedef enum JSExnType {
+    JSEXN_NONE = -1,
+      JSEXN_ERR,
+        JSEXN_INTERNALERR,
+        JSEXN_EVALERR,
+        JSEXN_RANGEERR,
+        JSEXN_REFERENCEERR,
+        JSEXN_SYNTAXERR,
+        JSEXN_TYPEERR,
+        JSEXN_URIERR,
+        JSEXN_LIMIT
+} JSExnType;
+
 typedef struct JSErrorFormatString {
-    const char *format;
-    uintN argCount;
+    const char *format;  /* the error message (may be UTF-8 if compiled with JS_C_STRINGS_ARE_UTF8) */
+    uint16 argCount;     /* the number of arguments to convert in the error message */
+    uint16 exnType;      /* One of the JSExnType constants above */
 } JSErrorFormatString;
 
 typedef const JSErrorFormatString *


ossp-pkg/js/src/jsstr.c -> 1.1.1.2

*** /dev/null    Sat Nov 23 05:07:35 2024
--- -    Sat Nov 23 05:07:42 2024
***************
*** 0 ****
--- 1,4845 ----
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  * vim: set ts=8 sw=4 et tw=80:
+  *
+  * ***** BEGIN LICENSE BLOCK *****
+  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+  *
+  * The contents of this file are subject to the Mozilla Public License Version
+  * 1.1 (the "License"); you may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at
+  * http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an "AS IS" basis,
+  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+  * for the specific language governing rights and limitations under the
+  * License.
+  *
+  * The Original Code is Mozilla Communicator client code, released
+  * March 31, 1998.
+  *
+  * The Initial Developer of the Original Code is
+  * Netscape Communications Corporation.
+  * Portions created by the Initial Developer are Copyright (C) 1998
+  * the Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s):
+  *
+  * Alternatively, the contents of this file may be used under the terms of
+  * either of the GNU General Public License Version 2 or later (the "GPL"),
+  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  * in which case the provisions of the GPL or the LGPL are applicable instead
+  * of those above. If you wish to allow use of your version of this file only
+  * under the terms of either the GPL or the LGPL, and not to allow others to
+  * use your version of this file under the terms of the MPL, indicate your
+  * decision by deleting the provisions above and replace them with the notice
+  * and other provisions required by the GPL or the LGPL. If you do not delete
+  * the provisions above, a recipient may use your version of this file under
+  * the terms of any one of the MPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+ 
+ /*
+  * JS string type implementation.
+  *
+  * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
+  * native methods store strings (possibly newborn) converted from their 'this'
+  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
+  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
+  * of rooting things that might lose their newborn root due to subsequent GC
+  * allocations in the same native method.
+  */
+ #include "jsstddef.h"
+ #include <stdlib.h>
+ #include <string.h>
+ #include "jstypes.h"
+ #include "jsutil.h" /* Added by JSIFY */
+ #include "jshash.h" /* Added by JSIFY */
+ #include "jsprf.h"
+ #include "jsapi.h"
+ #include "jsarray.h"
+ #include "jsatom.h"
+ #include "jsbool.h"
+ #include "jscntxt.h"
+ #include "jsconfig.h"
+ #include "jsgc.h"
+ #include "jsinterp.h"
+ #include "jslock.h"
+ #include "jsnum.h"
+ #include "jsobj.h"
+ #include "jsopcode.h"
+ #include "jsregexp.h"
+ #include "jsstr.h"
+ 
+ #if JS_HAS_REPLACE_LAMBDA
+ #include "jsinterp.h"
+ #endif
+ 
+ #define JSSTRDEP_RECURSION_LIMIT        100
+ 
+ size_t
+ js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
+ {
+     JSString *base;
+     size_t start, length;
+ 
+     JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
+     base = JSSTRDEP_BASE(str);
+     start = JSSTRDEP_START(str);
+     if (JSSTRING_IS_DEPENDENT(base)) {
+         if (level < JSSTRDEP_RECURSION_LIMIT) {
+             start += js_MinimizeDependentStrings(base, level + 1, &base);
+         } else {
+             do {
+                 start += JSSTRDEP_START(base);
+                 base = JSSTRDEP_BASE(base);
+             } while (JSSTRING_IS_DEPENDENT(base));
+         }
+         if (start == 0) {
+             JS_ASSERT(JSSTRING_IS_PREFIX(str));
+             JSPREFIX_SET_BASE(str, base);
+         } else if (start <= JSSTRDEP_START_MASK) {
+             length = JSSTRDEP_LENGTH(str);
+             JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
+             JSSTRDEP_SET_BASE(str, base);
+         }
+     }
+     *basep = base;
+     return start;
+ }
+ 
+ jschar *
+ js_GetDependentStringChars(JSString *str)
+ {
+     size_t start;
+     JSString *base;
+ 
+     start = js_MinimizeDependentStrings(str, 0, &base);
+     JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
+     JS_ASSERT(start < base->length);
+     return base->chars + start;
+ }
+ 
+ jschar *
+ js_GetStringChars(JSString *str)
+ {
+     if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(NULL, str))
+         return NULL;
+ 
+     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
+     return str->chars;
+ }
+ 
+ JSString *
+ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
+ {
+     size_t rn, ln, lrdist, n;
+     jschar *rs, *ls, *s;
+     JSDependentString *ldep;    /* non-null if left should become dependent */
+     JSString *str;
+ 
+     if (JSSTRING_IS_DEPENDENT(right)) {
+         rn = JSSTRDEP_LENGTH(right);
+         rs = JSSTRDEP_CHARS(right);
+     } else {
+         rn = right->length;
+         rs = right->chars;
+     }
+     if (rn == 0)
+         return left;
+ 
+     if (JSSTRING_IS_DEPENDENT(left) ||
+         !(*js_GetGCThingFlags(left) & GCF_MUTABLE)) {
+         /* We must copy if left does not own a buffer to realloc. */
+         ln = JSSTRING_LENGTH(left);
+         if (ln == 0)
+             return right;
+         ls = JSSTRING_CHARS(left);
+         s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
+         if (!s)
+             return NULL;
+         js_strncpy(s, ls, ln);
+         ldep = NULL;
+     } else {
+         /* We can realloc left's space and make it depend on our result. */
+         ln = left->length;
+         if (ln == 0)
+             return right;
+         ls = left->chars;
+         s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
+         if (!s)
+             return NULL;
+ 
+         /* Take care: right could depend on left! */
+         lrdist = (size_t)(rs - ls);
+         if (lrdist < ln)
+             rs = s + lrdist;
+         left->chars = ls = s;
+         ldep = JSSTRDEP(left);
+     }
+ 
+     js_strncpy(s + ln, rs, rn);
+     n = ln + rn;
+     s[n] = 0;
+     str = js_NewString(cx, s, n, GCF_MUTABLE);
+     if (!str) {
+         /* Out of memory: clean up any space we (re-)allocated. */
+         if (!ldep) {
+             JS_free(cx, s);
+         } else {
+             s = JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
+             if (s)
+                 left->chars = s;
+         }
+     } else {
+         /* Morph left into a dependent prefix if we realloc'd its buffer. */
+         if (ldep) {
+             JSPREFIX_SET_LENGTH(ldep, ln);
+             JSPREFIX_SET_BASE(ldep, str);
+ #ifdef DEBUG
+           {
+             JSRuntime *rt = cx->runtime;
+             JS_RUNTIME_METER(rt, liveDependentStrings);
+             JS_RUNTIME_METER(rt, totalDependentStrings);
+             JS_LOCK_RUNTIME_VOID(rt,
+                 (rt->strdepLengthSum += (double)ln,
+                  rt->strdepLengthSquaredSum += (double)ln * (double)ln));
+           }
+ #endif
+         }
+     }
+ 
+     return str;
+ }
+ 
+ /*
+  * May be called with null cx by js_GetStringChars, above; and by the jslock.c
+  * MAKE_STRING_IMMUTABLE file-local macro.
+  */
+ const jschar *
+ js_UndependString(JSContext *cx, JSString *str)
+ {
+     size_t n, size;
+     jschar *s;
+ 
+     if (JSSTRING_IS_DEPENDENT(str)) {
+         n = JSSTRDEP_LENGTH(str);
+         size = (n + 1) * sizeof(jschar);
+         s = (jschar *) (cx ? JS_malloc(cx, size) : malloc(size));
+         if (!s)
+             return NULL;
+ 
+         js_strncpy(s, JSSTRDEP_CHARS(str), n);
+         s[n] = 0;
+         str->length = n;
+         str->chars = s;
+ 
+ #ifdef DEBUG
+         if (cx) {
+             JSRuntime *rt = cx->runtime;
+             JS_RUNTIME_UNMETER(rt, liveDependentStrings);
+             JS_RUNTIME_UNMETER(rt, totalDependentStrings);
+             JS_LOCK_RUNTIME_VOID(rt,
+                 (rt->strdepLengthSum -= (double)n,
+                  rt->strdepLengthSquaredSum -= (double)n * (double)n));
+         }
+ #endif
+     }
+ 
+     return str->chars;
+ }
+ 
+ /*
+  * Forward declarations for URI encode/decode and helper routines
+  */
+ static JSBool
+ str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval);
+ 
+ static JSBool
+ str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                         jsval *rval);
+ 
+ static JSBool
+ str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval);
+ 
+ static JSBool
+ str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                         jsval *rval);
+ 
+ static uint32
+ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length);
+ 
+ /*
+  * Contributions from the String class to the set of methods defined for the
+  * global object.  escape and unescape used to be defined in the Mocha library,
+  * but as ECMA decided to spec them, they've been moved to the core engine
+  * and made ECMA-compliant.  (Incomplete escapes are interpreted as literal
+  * characters by unescape.)
+  */
+ 
+ /*
+  * Stuff to emulate the old libmocha escape, which took a second argument
+  * giving the type of escape to perform.  Retained for compatibility, and
+  * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
+  */
+ 
+ #define URL_XALPHAS     ((uint8) 1)
+ #define URL_XPALPHAS    ((uint8) 2)
+ #define URL_PATH        ((uint8) 4)
+ 
+ static const uint8 urlCharType[256] =
+ /*      Bit 0           xalpha          -- the alphas
+  *      Bit 1           xpalpha         -- as xalpha but
+  *                             converts spaces to plus and plus to %20
+  *      Bit 2 ...       path            -- as xalphas but doesn't escape '/'
+  */
+     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
+     {    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 0x */
+          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,       /* 1x */
+          0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,       /* 2x   !"#$%&'()*+,-./  */
+          7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,       /* 3x  0123456789:;<=>?  */
+          7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 4x  @ABCDEFGHIJKLMNO  */
+          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,       /* 5X  PQRSTUVWXYZ[\]^_  */
+          0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,       /* 6x  `abcdefghijklmno  */
+          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,       /* 7X  pqrstuvwxyz{\}~  DEL */
+          0, };
+ 
+ /* This matches the ECMA escape set when mask is 7 (default.) */
+ 
+ #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
+ 
+ /* See ECMA-262 15.1.2.4. */
+ JSBool
+ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+     size_t i, ni, length, newlength;
+     const jschar *chars;
+     jschar *newchars;
+     jschar ch;
+     jsint mask;
+     jsdouble d;
+     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ 
+     mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
+     if (argc > 1) {
+         if (!js_ValueToNumber(cx, argv[1], &d))
+             return JS_FALSE;
+         if (!JSDOUBLE_IS_FINITE(d) ||
+             (mask = (jsint)d) != d ||
+             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
+         {
+             char numBuf[12];
+             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
+             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                  JSMSG_BAD_STRING_MASK, numBuf);
+             return JS_FALSE;
+         }
+     }
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+ 
+     chars = JSSTRING_CHARS(str);
+     length = newlength = JSSTRING_LENGTH(str);
+ 
+     /* Take a first pass and see how big the result string will need to be. */
+     for (i = 0; i < length; i++) {
+         if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
+             continue;
+         if (ch < 256) {
+             if (mask == URL_XPALPHAS && ch == ' ')
+                 continue;   /* The character will be encoded as '+' */
+             newlength += 2; /* The character will be encoded as %XX */
+         } else {
+             newlength += 5; /* The character will be encoded as %uXXXX */
+         }
+ 
+         /*
+          * This overflow test works because newlength is incremented by at
+          * most 5 on each iteration.
+          */
+         if (newlength < length) {
+             JS_ReportOutOfMemory(cx);
+             return JS_FALSE;
+         }
+     }
+ 
+     if (newlength >= ~(size_t)0 / sizeof(jschar)) {
+         JS_ReportOutOfMemory(cx);
+         return JS_FALSE;
+     }
+ 
+     newchars = (jschar *) JS_malloc(cx, (newlength + 1) * sizeof(jschar));
+     if (!newchars)
+         return JS_FALSE;
+     for (i = 0, ni = 0; i < length; i++) {
+         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
+             newchars[ni++] = ch;
+         } else if (ch < 256) {
+             if (mask == URL_XPALPHAS && ch == ' ') {
+                 newchars[ni++] = '+'; /* convert spaces to pluses */
+             } else {
+                 newchars[ni++] = '%';
+                 newchars[ni++] = digits[ch >> 4];
+                 newchars[ni++] = digits[ch & 0xF];
+             }
+         } else {
+             newchars[ni++] = '%';
+             newchars[ni++] = 'u';
+             newchars[ni++] = digits[ch >> 12];
+             newchars[ni++] = digits[(ch & 0xF00) >> 8];
+             newchars[ni++] = digits[(ch & 0xF0) >> 4];
+             newchars[ni++] = digits[ch & 0xF];
+         }
+     }
+     JS_ASSERT(ni == newlength);
+     newchars[newlength] = 0;
+ 
+     str = js_NewString(cx, newchars, newlength, 0);
+     if (!str) {
+         JS_free(cx, newchars);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ #undef IS_OK
+ 
+ /* See ECMA-262 15.1.2.5 */
+ static JSBool
+ str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+     size_t i, ni, length;
+     const jschar *chars;
+     jschar *newchars;
+     jschar ch;
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+ 
+     chars = JSSTRING_CHARS(str);
+     length = JSSTRING_LENGTH(str);
+ 
+     /* Don't bother allocating less space for the new string. */
+     newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+     if (!newchars)
+         return JS_FALSE;
+     ni = i = 0;
+     while (i < length) {
+         ch = chars[i++];
+         if (ch == '%') {
+             if (i + 1 < length &&
+                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
+             {
+                 ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]);
+                 i += 2;
+             } else if (i + 4 < length && chars[i] == 'u' &&
+                        JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) &&
+                        JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4]))
+             {
+                 ch = (((((JS7_UNHEX(chars[i + 1]) << 4)
+                         + JS7_UNHEX(chars[i + 2])) << 4)
+                       + JS7_UNHEX(chars[i + 3])) << 4)
+                     + JS7_UNHEX(chars[i + 4]);
+                 i += 5;
+             }
+         }
+         newchars[ni++] = ch;
+     }
+     newchars[ni] = 0;
+ 
+     str = js_NewString(cx, newchars, ni, 0);
+     if (!str) {
+         JS_free(cx, newchars);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ #if JS_HAS_UNEVAL
+ static JSBool
+ str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToSource(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ #endif
+ 
+ const char js_escape_str[] = "escape";
+ const char js_unescape_str[] = "unescape";
+ #if JS_HAS_UNEVAL
+ const char js_uneval_str[] = "uneval";
+ #endif
+ const char js_decodeURI_str[] = "decodeURI";
+ const char js_encodeURI_str[] = "encodeURI";
+ const char js_decodeURIComponent_str[] = "decodeURIComponent";
+ const char js_encodeURIComponent_str[] = "encodeURIComponent";
+ 
+ static JSFunctionSpec string_functions[] = {
+     {js_escape_str,             js_str_escape,              1,0,0},
+     {js_unescape_str,           str_unescape,               1,0,0},
+ #if JS_HAS_UNEVAL
+     {js_uneval_str,             str_uneval,                 1,0,0},
+ #endif
+     {js_decodeURI_str,          str_decodeURI,              1,0,0},
+     {js_encodeURI_str,          str_encodeURI,              1,0,0},
+     {js_decodeURIComponent_str, str_decodeURI_Component,    1,0,0},
+     {js_encodeURIComponent_str, str_encodeURI_Component,    1,0,0},
+ 
+     {0,0,0,0,0}
+ };
+ 
+ jschar      js_empty_ucstr[]  = {0};
+ JSSubString js_EmptySubString = {0, js_empty_ucstr};
+ 
+ enum string_tinyid {
+     STRING_LENGTH = -1
+ };
+ 
+ static JSPropertySpec string_props[] = {
+     {js_length_str,     STRING_LENGTH,
+                         JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED, 0,0},
+     {0,0,0,0,0}
+ };
+ 
+ static JSBool
+ str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+ {
+     JSString *str;
+     jsint slot;
+ 
+     if (!JSVAL_IS_INT(id))
+         return JS_TRUE;
+ 
+     /*
+      * Call js_ValueToString because getters and setters can be invoked on
+      * objects of different class, unlike enumerate, resolve, and the other
+      * class hooks.
+      */
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+ 
+     slot = JSVAL_TO_INT(id);
+     if (slot == STRING_LENGTH)
+         *vp = INT_TO_JSVAL((jsint) JSSTRING_LENGTH(str));
+     return JS_TRUE;
+ }
+ 
+ #define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
+ 
+ static JSBool
+ str_enumerate(JSContext *cx, JSObject *obj)
+ {
+     JSString *str, *str1;
+     size_t i, length;
+ 
+     /* Avoid infinite recursion via js_obj_toSource (see bug 271477). */
+     if (JS_VERSION_IS_1_2(cx))
+         return JS_TRUE;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_TRUE;
+     cx->newborn[GCX_STRING] = (JSGCThing *) str;
+ 
+     length = JSSTRING_LENGTH(str);
+     for (i = 0; i < length; i++) {
+         str1 = js_NewDependentString(cx, str, i, 1, 0);
+         if (!str1)
+             return JS_FALSE;
+         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(i),
+                                  STRING_TO_JSVAL(str1), NULL, NULL,
+                                  STRING_ELEMENT_ATTRS, NULL)) {
+             return JS_FALSE;
+         }
+     }
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
+             JSObject **objp)
+ {
+     JSString *str, *str1;
+     jsint slot;
+ 
+     if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING))
+         return JS_TRUE;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_TRUE;
+     cx->newborn[GCX_STRING] = (JSGCThing *) str;
+ 
+     slot = JSVAL_TO_INT(id);
+     if ((size_t)slot < JSSTRING_LENGTH(str)) {
+         str1 = js_NewDependentString(cx, str, (size_t)slot, 1, 0);
+         if (!str1)
+             return JS_FALSE;
+         if (!OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(slot),
+                                  STRING_TO_JSVAL(str1), NULL, NULL,
+                                  STRING_ELEMENT_ATTRS, NULL)) {
+             return JS_FALSE;
+         }
+         *objp = obj;
+     }
+     return JS_TRUE;
+ }
+ 
+ JSClass js_StringClass = {
+     js_String_str,
+     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
+     JS_PropertyStub,   JS_PropertyStub,   str_getProperty,   JS_PropertyStub,
+     str_enumerate, (JSResolveOp)str_resolve, JS_ConvertStub, JS_FinalizeStub,
+     JSCLASS_NO_OPTIONAL_MEMBERS
+ };
+ 
+ #if JS_HAS_TOSOURCE
+ 
+ /*
+  * String.prototype.quote is generic (as are most string methods), unlike
+  * toSource, toString, and valueOf.
+  */
+ static JSBool
+ str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     str = js_QuoteString(cx, str, '"');
+     if (!str)
+         return JS_FALSE;
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     jsval v;
+     JSString *str;
+     size_t i, j, k, n;
+     char buf[16];
+     jschar *s, *t;
+ 
+     if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
+         return JS_FALSE;
+     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+     if (!JSVAL_IS_STRING(v))
+         return js_obj_toSource(cx, obj, argc, argv, rval);
+     str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
+     if (!str)
+         return JS_FALSE;
+     j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name);
+     s = JSSTRING_CHARS(str);
+     k = JSSTRING_LENGTH(str);
+     n = j + k + 2;
+     t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+     if (!t)
+         return JS_FALSE;
+     for (i = 0; i < j; i++)
+         t[i] = buf[i];
+     for (j = 0; j < k; i++, j++)
+         t[i] = s[j];
+     t[i++] = ')';
+     t[i++] = ')';
+     t[i] = 0;
+     str = js_NewString(cx, t, n, 0);
+     if (!str) {
+         JS_free(cx, t);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ #endif /* JS_HAS_TOSOURCE */
+ 
+ static JSBool
+ str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     jsval v;
+ 
+     if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
+         return JS_FALSE;
+     v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+     if (!JSVAL_IS_STRING(v))
+         return js_obj_toString(cx, obj, argc, argv, rval);
+     *rval = v;
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     if (!JS_InstanceOf(cx, obj, &js_StringClass, argv))
+         return JS_FALSE;
+     *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+     return JS_TRUE;
+ }
+ 
+ /*
+  * Java-like string native methods.
+  */
+ static JSBool
+ str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval)
+ {
+     JSString *str;
+     jsdouble d;
+     jsdouble length, begin, end;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc != 0) {
+         if (!js_ValueToNumber(cx, argv[0], &d))
+             return JS_FALSE;
+         length = JSSTRING_LENGTH(str);
+         begin = js_DoubleToInteger(d);
+         if (begin < 0)
+             begin = 0;
+         else if (begin > length)
+             begin = length;
+ 
+         if (argc == 1) {
+             end = length;
+         } else {
+             if (!js_ValueToNumber(cx, argv[1], &d))
+                 return JS_FALSE;
+             end = js_DoubleToInteger(d);
+             if (end < 0)
+                 end = 0;
+             else if (end > length)
+                 end = length;
+             if (end < begin) {
+                 if (!JS_VERSION_IS_1_2(cx)) {
+                     /* XXX emulate old JDK1.0 java.lang.String.substring. */
+                     jsdouble tmp = begin;
+                     begin = end;
+                     end = tmp;
+                 } else {
+                     end = begin;
+                 }
+             }
+         }
+ 
+         str = js_NewDependentString(cx, str, (size_t)begin,
+                                     (size_t)(end - begin), 0);
+         if (!str)
+             return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval)
+ {
+     JSString *str;
+     size_t i, n;
+     jschar *s, *news;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     n = JSSTRING_LENGTH(str);
+     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+     if (!news)
+         return JS_FALSE;
+     s = JSSTRING_CHARS(str);
+     for (i = 0; i < n; i++)
+         news[i] = JS_TOLOWER(s[i]);
+     news[n] = 0;
+     str = js_NewString(cx, news, n, 0);
+     if (!str) {
+         JS_free(cx, news);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval)
+ {
+     JSString *str;
+ 
+     /*
+      * Forcefully ignore the first (or any) argument and return toLowerCase(),
+      * ECMA has reserved that argument, presumably for defining the locale.
+      */
+     if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
+         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+         if (!str)
+             return JS_FALSE;
+         argv[-1] = STRING_TO_JSVAL(str);
+         return cx->localeCallbacks->localeToLowerCase(cx, str, rval);
+     }
+     return str_toLowerCase(cx, obj, 0, argv, rval);
+ }
+ 
+ static JSBool
+ str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval)
+ {
+     JSString *str;
+     size_t i, n;
+     jschar *s, *news;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     n = JSSTRING_LENGTH(str);
+     news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
+     if (!news)
+         return JS_FALSE;
+     s = JSSTRING_CHARS(str);
+     for (i = 0; i < n; i++)
+         news[i] = JS_TOUPPER(s[i]);
+     news[n] = 0;
+     str = js_NewString(cx, news, n, 0);
+     if (!str) {
+         JS_free(cx, news);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval)
+ {
+     JSString *str;
+ 
+     /*
+      * Forcefully ignore the first (or any) argument and return toUpperCase(),
+      * ECMA has reserved that argument, presumbaly for defining the locale.
+      */
+     if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
+         str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+         if (!str)
+             return JS_FALSE;
+         argv[-1] = STRING_TO_JSVAL(str);
+         return cx->localeCallbacks->localeToUpperCase(cx, str, rval);
+     }
+     return str_toUpperCase(cx, obj, 0, argv, rval);
+ }
+ 
+ static JSBool
+ str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                   jsval *rval)
+ {
+     JSString *str, *thatStr;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc == 0) {
+         *rval = JSVAL_ZERO;
+     } else {
+         thatStr = js_ValueToString(cx, argv[0]);
+         if (!thatStr)
+             return JS_FALSE;
+         if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
+             argv[0] = STRING_TO_JSVAL(thatStr);
+             return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval);
+         }
+         *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
+     }
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+     jsdouble d;
+     size_t index;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc == 0) {
+         d = 0.0;
+     } else {
+         if (!js_ValueToNumber(cx, argv[0], &d))
+             return JS_FALSE;
+         d = js_DoubleToInteger(d);
+     }
+ 
+     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
+         *rval = JS_GetEmptyStringValue(cx);
+     } else {
+         index = (size_t)d;
+         str = js_NewDependentString(cx, str, index, 1, 0);
+         if (!str)
+             return JS_FALSE;
+         *rval = STRING_TO_JSVAL(str);
+     }
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                jsval *rval)
+ {
+     JSString *str;
+     jsdouble d;
+     size_t index;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc == 0) {
+         d = 0.0;
+     } else {
+         if (!js_ValueToNumber(cx, argv[0], &d))
+             return JS_FALSE;
+         d = js_DoubleToInteger(d);
+     }
+ 
+     if (d < 0 || JSSTRING_LENGTH(str) <= d) {
+         *rval = JS_GetNaNValue(cx);
+     } else {
+         index = (size_t)d;
+         *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]);
+     }
+     return JS_TRUE;
+ }
+ 
+ jsint
+ js_BoyerMooreHorspool(const jschar *text, jsint textlen,
+                       const jschar *pat, jsint patlen,
+                       jsint start)
+ {
+     jsint i, j, k, m;
+     uint8 skip[BMH_CHARSET_SIZE];
+     jschar c;
+ 
+     JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
+     for (i = 0; i < BMH_CHARSET_SIZE; i++)
+         skip[i] = (uint8)patlen;
+     m = patlen - 1;
+     for (i = 0; i < m; i++) {
+         c = pat[i];
+         if (c >= BMH_CHARSET_SIZE)
+             return BMH_BAD_PATTERN;
+         skip[c] = (uint8)(m - i);
+     }
+     for (k = start + m;
+          k < textlen;
+          k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
+         for (i = k, j = m; ; i--, j--) {
+             if (j < 0)
+                 return i + 1;
+             if (text[i] != pat[j])
+                 break;
+         }
+     }
+     return -1;
+ }
+ 
+ static JSBool
+ str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str, *str2;
+     jsint i, j, index, textlen, patlen;
+     const jschar *text, *pat;
+     jsdouble d;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+     text = JSSTRING_CHARS(str);
+     textlen = (jsint) JSSTRING_LENGTH(str);
+ 
+     str2 = js_ValueToString(cx, argv[0]);
+     if (!str2)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str2);
+     pat = JSSTRING_CHARS(str2);
+     patlen = (jsint) JSSTRING_LENGTH(str2);
+ 
+     if (argc > 1) {
+         if (!js_ValueToNumber(cx, argv[1], &d))
+             return JS_FALSE;
+         d = js_DoubleToInteger(d);
+         if (d < 0)
+             i = 0;
+         else if (d > textlen)
+             i = textlen;
+         else
+             i = (jsint)d;
+     } else {
+         i = 0;
+     }
+     if (patlen == 0) {
+         *rval = INT_TO_JSVAL(i);
+         return JS_TRUE;
+     }
+ 
+     /* XXX tune the BMH threshold (512) */
+     if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) {
+         index = js_BoyerMooreHorspool(text, textlen, pat, patlen, i);
+         if (index != BMH_BAD_PATTERN)
+             goto out;
+     }
+ 
+     index = -1;
+     j = 0;
+     while (i + j < textlen) {
+         if (text[i + j] == pat[j]) {
+             if (++j == patlen) {
+                 index = i;
+                 break;
+             }
+         } else {
+             i++;
+             j = 0;
+         }
+     }
+ 
+ out:
+     *rval = INT_TO_JSVAL(index);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                   jsval *rval)
+ {
+     JSString *str, *str2;
+     const jschar *text, *pat;
+     jsint i, j, textlen, patlen;
+     jsdouble d;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+     text = JSSTRING_CHARS(str);
+     textlen = (jsint) JSSTRING_LENGTH(str);
+ 
+     str2 = js_ValueToString(cx, argv[0]);
+     if (!str2)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str2);
+     pat = JSSTRING_CHARS(str2);
+     patlen = (jsint) JSSTRING_LENGTH(str2);
+ 
+     if (argc > 1) {
+         if (!js_ValueToNumber(cx, argv[1], &d))
+             return JS_FALSE;
+         if (JSDOUBLE_IS_NaN(d)) {
+             i = textlen;
+         } else {
+             d = js_DoubleToInteger(d);
+             if (d < 0)
+                 i = 0;
+             else if (d > textlen)
+                 i = textlen;
+             else
+                 i = (jsint)d;
+         }
+     } else {
+         i = textlen;
+     }
+ 
+     if (patlen == 0) {
+         *rval = INT_TO_JSVAL(i);
+         return JS_TRUE;
+     }
+ 
+     j = 0;
+     while (i >= 0) {
+         /* Don't assume that text is NUL-terminated: it could be dependent. */
+         if (i + j < textlen && text[i + j] == pat[j]) {
+             if (++j == patlen)
+                 break;
+         } else {
+             i--;
+             j = 0;
+         }
+     }
+     *rval = INT_TO_JSVAL(i);
+     return JS_TRUE;
+ }
+ 
+ /*
+  * Perl-inspired string functions.
+  */
+ #if JS_HAS_REGEXPS
+ typedef struct GlobData {
+     uintN       flags;          /* inout: mode and flag bits, see below */
+     uintN       optarg;         /* in: index of optional flags argument */
+     JSString    *str;           /* out: 'this' parameter object as string */
+     JSRegExp    *regexp;        /* out: regexp parameter object private data */
+ } GlobData;
+ 
+ /*
+  * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
+  */
+ #define MODE_MATCH      0x00    /* in: return match array on success */
+ #define MODE_REPLACE    0x01    /* in: match and replace */
+ #define MODE_SEARCH     0x02    /* in: search only, return match index or -1 */
+ #define GET_MODE(f)     ((f) & 0x03)
+ #define FORCE_FLAT      0x04    /* in: force flat (non-regexp) string match */
+ #define KEEP_REGEXP     0x08    /* inout: keep GlobData.regexp alive for caller
+                                           of match_or_replace; if set on input
+                                           but clear on output, regexp ownership
+                                           does not pass to caller */
+ #define GLOBAL_REGEXP   0x10    /* out: regexp had the 'g' flag */
+ 
+ static JSBool
+ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                  JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
+                  GlobData *data, jsval *rval)
+ {
+     JSString *str, *src, *opt;
+     JSObject *reobj;
+     JSRegExp *re;
+     size_t index, length;
+     JSBool ok, test;
+     jsint count;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+     data->str = str;
+ 
+     if (JSVAL_IS_REGEXP(cx, argv[0])) {
+         reobj = JSVAL_TO_OBJECT(argv[0]);
+         re = (JSRegExp *) JS_GetPrivate(cx, reobj);
+     } else {
+         src = js_ValueToString(cx, argv[0]);
+         if (!src)
+             return JS_FALSE;
+         if (data->optarg < argc) {
+             argv[0] = STRING_TO_JSVAL(src);
+             opt = js_ValueToString(cx, argv[data->optarg]);
+             if (!opt)
+                 return JS_FALSE;
+         } else {
+             opt = NULL;
+         }
+         re = js_NewRegExpOpt(cx, NULL, src, opt,
+                              (data->flags & FORCE_FLAT) != 0);
+         if (!re)
+             return JS_FALSE;
+         reobj = NULL;
+     }
+     data->regexp = re;
+ 
+     if (re->flags & JSREG_GLOB)
+         data->flags |= GLOBAL_REGEXP;
+     index = 0;
+     if (GET_MODE(data->flags) == MODE_SEARCH) {
+         ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
+         if (ok) {
+             *rval = (*rval == JSVAL_TRUE)
+                     ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
+                     : INT_TO_JSVAL(-1);
+         }
+     } else if (data->flags & GLOBAL_REGEXP) {
+         if (reobj) {
+             /* Set the lastIndex property's reserved slot to 0. */
+             ok = js_SetLastIndex(cx, reobj, 0);
+             if (!ok)
+                 return JS_FALSE;
+         } else {
+             ok = JS_TRUE;
+         }
+         length = JSSTRING_LENGTH(str);
+         for (count = 0; index <= length; count++) {
+             ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval);
+             if (!ok || *rval != JSVAL_TRUE)
+                 break;
+             ok = glob(cx, count, data);
+             if (!ok)
+                 break;
+             if (cx->regExpStatics.lastMatch.length == 0) {
+                 if (index == length)
+                     break;
+                 index++;
+             }
+         }
+     } else {
+         if (GET_MODE(data->flags) == MODE_REPLACE) {
+             test = JS_TRUE;
+         } else {
+             /*
+              * MODE_MATCH implies str_match is being called from a script or a
+              * scripted function.  If the caller cares only about testing null
+              * vs. non-null return value, optimize away the array object that
+              * would normally be returned in *rval.
+              */
+             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);
+     }
+ 
+     if (reobj) {
+         /* Tell our caller that it doesn't need to destroy data->regexp. */
+         data->flags &= ~KEEP_REGEXP;
+     } else if (!(data->flags & KEEP_REGEXP)) {
+         /* Caller didn't want to keep data->regexp, so null and destroy it.  */
+         data->regexp = NULL;
+         js_DestroyRegExp(cx, re);
+     }
+     return ok;
+ }
+ 
+ typedef struct MatchData {
+     GlobData    base;
+     jsval       *arrayval;      /* NB: local root pointer */
+ } MatchData;
+ 
+ static JSBool
+ match_glob(JSContext *cx, jsint count, GlobData *data)
+ {
+     MatchData *mdata;
+     JSObject *arrayobj;
+     JSSubString *matchsub;
+     JSString *matchstr;
+     jsval v;
+ 
+     mdata = (MatchData *)data;
+     arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
+     if (!arrayobj) {
+         arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
+         if (!arrayobj)
+             return JS_FALSE;
+         *mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
+     }
+     matchsub = &cx->regExpStatics.lastMatch;
+     matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length, 0);
+     if (!matchstr)
+         return JS_FALSE;
+     v = STRING_TO_JSVAL(matchstr);
+     return js_SetProperty(cx, arrayobj, INT_TO_JSID(count), &v);
+ }
+ 
+ static JSBool
+ str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     MatchData mdata;
+     JSBool ok;
+ 
+     mdata.base.flags = MODE_MATCH;
+     mdata.base.optarg = 1;
+     mdata.arrayval = &argv[2];
+     *mdata.arrayval = JSVAL_NULL;
+     ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
+     if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
+         *rval = *mdata.arrayval;
+     return ok;
+ }
+ 
+ static JSBool
+ str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     GlobData data;
+ 
+     data.flags = MODE_SEARCH;
+     data.optarg = 1;
+     return match_or_replace(cx, obj, argc, argv, NULL, &data, rval);
+ }
+ 
+ typedef struct ReplaceData {
+     GlobData    base;           /* base struct state */
+     JSObject    *lambda;        /* replacement function object or null */
+     JSString    *repstr;        /* replacement string */
+     jschar      *dollar;        /* null or pointer to first $ in repstr */
+     jschar      *dollarEnd;     /* limit pointer for js_strchr_limit */
+     jschar      *chars;         /* result chars, null initially */
+     size_t      length;         /* result length, 0 initially */
+     jsint       index;          /* index in result of next replacement */
+     jsint       leftIndex;      /* left context index in base.str->chars */
+     JSSubString dollarStr;      /* for "$$" interpret_dollar result */
+ } ReplaceData;
+ 
+ static JSSubString *
+ interpret_dollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData *rdata,
+                  size_t *skip)
+ {
+     JSVersion version;
+     JSRegExpStatics *res;
+     jschar dc, *cp;
+     uintN num, tmp;
+     JSString *str;
+ 
+     JS_ASSERT(*dp == '$');
+ 
+     /*
+      * Allow a real backslash (literal "\\" before "$1") to escape "$1", e.g.
+      * Do this only for versions strictly less than ECMAv3.
+      */
+     version = cx->version & JSVERSION_MASK;
+     if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) {
+         if (dp > JSSTRING_CHARS(rdata->repstr) && dp[-1] == '\\')
+             return NULL;
+     }
+ 
+     /* If there is only a dollar, bail now */
+     if (dp + 1 >= ep)
+         return NULL;
+ 
+     /* Interpret all Perl match-induced dollar variables. */
+     res = &cx->regExpStatics;
+     dc = dp[1];
+     if (JS7_ISDEC(dc)) {
+         if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4) {
+             if (dc == '0')
+                 return NULL;
+ 
+             /* Check for overflow to avoid gobbling arbitrary decimal digits. */
+             num = 0;
+             cp = dp;
+             while (++cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
+                 tmp = 10 * num + JS7_UNDEC(dc);
+                 if (tmp < num)
+                     break;
+                 num = tmp;
+             }
+         } else { /* ECMA 3, 1-9 or 01-99 */
+             num = JS7_UNDEC(dc);
+             if (num > res->parenCount)
+                 return NULL;
+ 
+             cp = dp + 2;
+             if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
+                 tmp = 10 * num + JS7_UNDEC(dc);
+                 if (tmp <= res->parenCount) {
+                     cp++;
+                     num = tmp;
+                 }
+             }
+             if (num == 0)
+                 return NULL;
+         }
+         /* Adjust num from 1 $n-origin to 0 array-index-origin. */
+         num--;
+         *skip = cp - dp;
+         return REGEXP_PAREN_SUBSTRING(res, num);
+     }
+ 
+     *skip = 2;
+     switch (dc) {
+       case '$':
+         rdata->dollarStr.chars = dp;
+         rdata->dollarStr.length = 1;
+         return &rdata->dollarStr;
+       case '&':
+         return &res->lastMatch;
+       case '+':
+         return &res->lastParen;
+       case '`':
+         if (version == JSVERSION_1_2) {
+             /*
+              * JS1.2 imitated the Perl4 bug where left context at each step
+              * in an iterative use of a global regexp started from last match,
+              * not from the start of the target string.  But Perl4 does start
+              * $` at the beginning of the target string when it is used in a
+              * substitution, so we emulate that special case here.
+              */
+             str = rdata->base.str;
+             res->leftContext.chars = JSSTRING_CHARS(str);
+             res->leftContext.length = res->lastMatch.chars
+                                     - JSSTRING_CHARS(str);
+         }
+         return &res->leftContext;
+       case '\'':
+         return &res->rightContext;
+     }
+     return NULL;
+ }
+ 
+ static JSBool
+ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
+ {
+     JSString *repstr;
+     size_t replen, skip;
+     jschar *dp, *ep;
+     JSSubString *sub;
+ #if JS_HAS_REPLACE_LAMBDA
+     JSObject *lambda;
+ 
+     lambda = rdata->lambda;
+     if (lambda) {
+         uintN argc, i, j, m, n, p;
+         jsval *sp, *oldsp, rval;
+         void *mark;
+         JSStackFrame *fp;
+         JSBool ok;
+ 
+         /*
+          * Save the regExpStatics from the current regexp, since they may be
+          * clobbered by a RegExp usage in the lambda function.  Note that all
+          * members of JSRegExpStatics are JSSubStrings, so not GC roots, save
+          * input, which is rooted otherwise via argv[-1] in str_replace.
+          */
+         JSRegExpStatics save = cx->regExpStatics;
+         JSBool freeMoreParens = JS_FALSE;
+ 
+         /*
+          * In the lambda case, not only do we find the replacement string's
+          * length, we compute repstr and return it via rdata for use within
+          * do_replace.  The lambda is called with arguments ($&, $1, $2, ...,
+          * index, input), i.e., all the properties of a regexp match array.
+          * For $&, etc., we must create string jsvals from cx->regExpStatics.
+          * We grab up stack space to keep the newborn strings GC-rooted.
+          */
+         p = rdata->base.regexp->parenCount;
+         argc = 1 + p + 2;
+         sp = js_AllocStack(cx, 2 + argc, &mark);
+         if (!sp)
+             return JS_FALSE;
+ 
+         /* Push lambda and its 'this' parameter. */
+         *sp++ = OBJECT_TO_JSVAL(lambda);
+         *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
+ 
+ #define PUSH_REGEXP_STATIC(sub)                                               \
+     JS_BEGIN_MACRO                                                            \
+         JSString *str = js_NewStringCopyN(cx,                                 \
+                                           cx->regExpStatics.sub.chars,        \
+                                           cx->regExpStatics.sub.length,       \
+                                           0);                                 \
+         if (!str) {                                                           \
+             ok = JS_FALSE;                                                    \
+             goto lambda_out;                                                  \
+         }                                                                     \
+         *sp++ = STRING_TO_JSVAL(str);                                         \
+     JS_END_MACRO
+ 
+         /* Push $&, $1, $2, ... */
+         PUSH_REGEXP_STATIC(lastMatch);
+         i = 0;
+         m = cx->regExpStatics.parenCount;
+         n = JS_MIN(m, 9);
+         for (j = 0; i < n; i++, j++)
+             PUSH_REGEXP_STATIC(parens[j]);
+         for (j = 0; i < m; i++, j++)
+             PUSH_REGEXP_STATIC(moreParens[j]);
+ 
+         /*
+          * We need to clear moreParens in the top-of-stack cx->regExpStatics
+          * to it won't be possibly realloc'ed, leaving the bottom-of-stack
+          * moreParens pointing to freed memory.
+          */
+         cx->regExpStatics.moreParens = NULL;
+         freeMoreParens = JS_TRUE;
+ 
+ #undef PUSH_REGEXP_STATIC
+ 
+         /* Make sure to push undefined for any unmatched parens. */
+         for (; i < p; i++)
+             *sp++ = JSVAL_VOID;
+ 
+         /* Push match index and input string. */
+         *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
+         *sp++ = STRING_TO_JSVAL(rdata->base.str);
+ 
+         /* Lift current frame to include the args and do the call. */
+         fp = cx->fp;
+         oldsp = fp->sp;
+         fp->sp = sp;
+         ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
+         rval = fp->sp[-1];
+         fp->sp = oldsp;
+ 
+         if (ok) {
+             /*
+              * NB: we count on the newborn string root to hold any string
+              * created by this js_ValueToString that would otherwise be GC-
+              * able, until we use rdata->repstr in do_replace.
+              */
+             repstr = js_ValueToString(cx, rval);
+             if (!repstr) {
+                 ok = JS_FALSE;
+             } else {
+                 rdata->repstr = repstr;
+                 *sizep = JSSTRING_LENGTH(repstr);
+             }
+         }
+ 
+       lambda_out:
+         js_FreeStack(cx, mark);
+         if (freeMoreParens)
+             JS_free(cx, cx->regExpStatics.moreParens);
+         cx->regExpStatics = save;
+         return ok;
+     }
+ #endif /* JS_HAS_REPLACE_LAMBDA */
+ 
+     repstr = rdata->repstr;
+     replen = JSSTRING_LENGTH(repstr);
+     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
+          dp = js_strchr_limit(dp, '$', ep)) {
+         sub = interpret_dollar(cx, dp, ep, rdata, &skip);
+         if (sub) {
+             replen += sub->length - skip;
+             dp += skip;
+         }
+         else
+             dp++;
+     }
+     *sizep = replen;
+     return JS_TRUE;
+ }
+ 
+ static void
+ do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
+ {
+     JSString *repstr;
+     jschar *bp, *cp, *dp, *ep;
+     size_t len, skip;
+     JSSubString *sub;
+ 
+     repstr = rdata->repstr;
+     bp = cp = JSSTRING_CHARS(repstr);
+     for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;
+          dp = js_strchr_limit(dp, '$', ep)) {
+         len = dp - cp;
+         js_strncpy(chars, cp, len);
+         chars += len;
+         cp = dp;
+         sub = interpret_dollar(cx, dp, ep, rdata, &skip);
+         if (sub) {
+             len = sub->length;
+             js_strncpy(chars, sub->chars, len);
+             chars += len;
+             cp += skip;
+             dp += skip;
+         } else {
+             dp++;
+         }
+     }
+     js_strncpy(chars, cp, JSSTRING_LENGTH(repstr) - (cp - bp));
+ }
+ 
+ static JSBool
+ replace_glob(JSContext *cx, jsint count, GlobData *data)
+ {
+     ReplaceData *rdata;
+     JSString *str;
+     size_t leftoff, leftlen, replen, growth;
+     const jschar *left;
+     jschar *chars;
+ 
+     rdata = (ReplaceData *)data;
+     str = data->str;
+     leftoff = rdata->leftIndex;
+     left = JSSTRING_CHARS(str) + leftoff;
+     leftlen = cx->regExpStatics.lastMatch.chars - left;
+     rdata->leftIndex = cx->regExpStatics.lastMatch.chars - JSSTRING_CHARS(str);
+     rdata->leftIndex += cx->regExpStatics.lastMatch.length;
+     if (!find_replen(cx, rdata, &replen))
+         return JS_FALSE;
+     growth = leftlen + replen;
+     chars = (jschar *)
+         (rdata->chars
+          ? JS_realloc(cx, rdata->chars, (rdata->length + growth + 1)
+                                         * sizeof(jschar))
+          : JS_malloc(cx, (growth + 1) * sizeof(jschar)));
+     if (!chars) {
+         JS_free(cx, rdata->chars);
+         rdata->chars = NULL;
+         return JS_FALSE;
+     }
+     rdata->chars = chars;
+     rdata->length += growth;
+     chars += rdata->index;
+     rdata->index += growth;
+     js_strncpy(chars, left, leftlen);
+     chars += leftlen;
+     do_replace(cx, rdata, chars);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSObject *lambda;
+     JSString *repstr, *str;
+     ReplaceData rdata;
+     JSVersion version;
+     JSBool ok;
+     jschar *chars;
+     size_t leftlen, rightlen, length;
+ 
+ #if JS_HAS_REPLACE_LAMBDA
+     if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {
+         lambda = JSVAL_TO_OBJECT(argv[1]);
+         repstr = NULL;
+     } else
+ #endif
+     {
+         if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))
+             return JS_FALSE;
+         repstr = JSVAL_TO_STRING(argv[1]);
+         lambda = NULL;
+     }
+ 
+     /*
+      * For ECMA Edition 3, the first argument is to be converted to a string
+      * to match in a "flat" sense (without regular expression metachars having
+      * special meanings) UNLESS the first arg is a RegExp object.
+      */
+     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP;
+     version = cx->version & JSVERSION_MASK;
+     if (version == JSVERSION_DEFAULT || version > JSVERSION_1_4)
+         rdata.base.flags |= FORCE_FLAT;
+     rdata.base.optarg = 2;
+ 
+     rdata.lambda = lambda;
+     rdata.repstr = repstr;
+     if (repstr) {
+         rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr);
+         rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$',
+                                        rdata.dollarEnd);
+     } else {
+         rdata.dollar = rdata.dollarEnd = NULL;
+     }
+     rdata.chars = NULL;
+     rdata.length = 0;
+     rdata.index = 0;
+     rdata.leftIndex = 0;
+ 
+     ok = match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval);
+     if (!ok)
+         return JS_FALSE;
+ 
+     if (!rdata.chars) {
+         if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) {
+             /* Didn't match even once. */
+             *rval = STRING_TO_JSVAL(rdata.base.str);
+             goto out;
+         }
+         leftlen = cx->regExpStatics.leftContext.length;
+         ok = find_replen(cx, &rdata, &length);
+         if (!ok)
+             goto out;
+         length += leftlen;
+         chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+         if (!chars) {
+             ok = JS_FALSE;
+             goto out;
+         }
+         js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);
+         do_replace(cx, &rdata, chars + leftlen);
+         rdata.chars = chars;
+         rdata.length = length;
+     }
+ 
+     rightlen = cx->regExpStatics.rightContext.length;
+     length = rdata.length + rightlen;
+     chars = (jschar *)
+         JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));
+     if (!chars) {
+         JS_free(cx, rdata.chars);
+         ok = JS_FALSE;
+         goto out;
+     }
+     js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,
+                rightlen);
+     chars[length] = 0;
+ 
+     str = js_NewString(cx, chars, length, 0);
+     if (!str) {
+         JS_free(cx, chars);
+         ok = JS_FALSE;
+         goto out;
+     }
+     *rval = STRING_TO_JSVAL(str);
+ 
+ out:
+     /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
+     if (rdata.base.flags & KEEP_REGEXP)
+         js_DestroyRegExp(cx, rdata.base.regexp);
+     return ok;
+ }
+ #endif /* JS_HAS_REGEXPS */
+ 
+ /*
+  * Subroutine used by str_split to find the next split point in str, starting
+  * at offset *ip and looking either for the separator substring given by sep,
+  * or for the next re match.  In the re case, return the matched separator in
+  * *sep, and the possibly updated offset in *ip.
+  *
+  * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
+  * separator occurrence if found, or str->length if no separator is found.
+  */
+ static jsint
+ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
+            JSSubString *sep)
+ {
+     jsint i, j, k;
+     jschar *chars;
+     size_t length;
+ 
+     /*
+      * Stop if past end of string.  If at end of string, we will compare the
+      * null char stored there (by js_NewString*) to sep->chars[j] in the while
+      * loop at the end of this function, so that
+      *
+      *  "ab,".split(',') => ["ab", ""]
+      *
+      * and the resulting array converts back to the string "ab," for symmetry.
+      * However, we ape Perl and do this only if there is a sufficiently large
+      * limit argument (see str_split).
+      */
+     i = *ip;
+     if ((size_t)i > JSSTRING_LENGTH(str))
+         return -1;
+ 
+     /*
+      * Perl4 special case for str.split(' '), only if the user has selected
+      * JavaScript1.2 explicitly.  Split on whitespace, and skip leading w/s.
+      * Strange but true, apparently modeled after awk.
+      *
+      * NB: we set sep->length to the length of the w/s run, so we must test
+      * sep->chars[1] == 0 to make sure sep is just one space.
+      */
+     chars = JSSTRING_CHARS(str);
+     length = JSSTRING_LENGTH(str);
+     if (JS_VERSION_IS_1_2(cx) &&
+         !re && *sep->chars == ' ' && sep->chars[1] == 0) {
+ 
+         /* Skip leading whitespace if at front of str. */
+         if (i == 0) {
+             while (JS_ISSPACE(chars[i]))
+                 i++;
+             *ip = i;
+         }
+ 
+         /* Don't delimit whitespace at end of string. */
+         if ((size_t)i == length)
+             return -1;
+ 
+         /* Skip over the non-whitespace chars. */
+         while ((size_t)i < length && !JS_ISSPACE(chars[i]))
+             i++;
+ 
+         /* Now skip the next run of whitespace. */
+         j = i;
+         while ((size_t)j < length && JS_ISSPACE(chars[j]))
+             j++;
+ 
+         /* Update sep->length to count delimiter chars. */
+         sep->length = (size_t)(j - i);
+         return i;
+     }
+ 
+ #if JS_HAS_REGEXPS
+     /*
+      * Match a regular expression against the separator at or above index i.
+      * Call js_ExecuteRegExp with true for the test argument.  On successful
+      * match, get the separator from cx->regExpStatics.lastMatch.
+      */
+     if (re) {
+         size_t index;
+         jsval rval;
+ 
+       again:
+         /* JS1.2 deviated from Perl by never matching at end of string. */
+         index = (size_t)i;
+         if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
+             return -2;
+         if (rval != JSVAL_TRUE) {
+             /* Mismatch: ensure our caller advances i past end of string. */
+             sep->length = 1;
+             return length;
+         }
+         i = (jsint)index;
+         *sep = cx->regExpStatics.lastMatch;
+         if (sep->length == 0) {
+             /*
+              * Empty string match: never split on an empty match at the start
+              * of a find_split cycle.  Same rule as for an empty global match
+              * in match_or_replace.
+              */
+             if (i == *ip) {
+                 /*
+                  * "Bump-along" to avoid sticking at an empty match, but don't
+                  * bump past end of string -- our caller must do that by adding
+                  * sep->length to our return value.
+                  */
+                 if ((size_t)i == length) {
+                     if (JS_VERSION_IS_1_2(cx)) {
+                         sep->length = 1;
+                         return i;
+                     }
+                     return -1;
+                 }
+                 i++;
+                 goto again;
+             }
+             if ((size_t)i == length) {
+                 /*
+                  * If there was a trivial zero-length match at the end of the
+                  * split, then we shouldn't output the matched string at the end
+                  * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15.
+                  */
+                 sep->chars = NULL;
+             }
+         }
+         JS_ASSERT((size_t)i >= sep->length);
+         return i - sep->length;
+     }
+ #endif /* JS_HAS_REGEXPS */
+ 
+     /*
+      * Deviate from ECMA by never splitting an empty string by any separator
+      * string into a non-empty array (an array of length 1 that contains the
+      * empty string).
+      */
+     if (!JS_VERSION_IS_ECMA(cx) && length == 0)
+         return -1;
+ 
+     /*
+      * Special case: if sep is the empty string, split str into one character
+      * substrings.  Let our caller worry about whether to split once at end of
+      * string into an empty substring.
+      *
+      * For 1.2 compatibility, at the end of the string, we return the length as
+      * the result, and set the separator length to 1 -- this allows the caller
+      * to include an additional null string at the end of the substring list.
+      */
+     if (sep->length == 0) {
+         if (JS_VERSION_IS_1_2(cx)) {
+             if ((size_t)i == length) {
+                 sep->length = 1;
+                 return i;
+             }
+             return i + 1;
+         }
+         return ((size_t)i == length) ? -1 : i + 1;
+     }
+ 
+     /*
+      * Now that we know sep is non-empty, search starting at i in str for an
+      * occurrence of all of sep's chars.  If we find them, return the index of
+      * the first separator char.  Otherwise, return length.
+      */
+     j = 0;
+     while ((size_t)(k = i + j) < length) {
+         if (chars[k] == sep->chars[j]) {
+             if ((size_t)++j == sep->length)
+                 return i;
+         } else {
+             i++;
+             j = 0;
+         }
+     }
+     return k;
+ }
+ 
+ static JSBool
+ str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str, *sub;
+     JSObject *arrayobj;
+     jsval v;
+     JSBool ok, limited;
+     JSRegExp *re;
+     JSSubString *sep, tmp;
+     jsdouble d;
+     jsint i, j;
+     uint32 len, limit;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
+     if (!arrayobj)
+         return JS_FALSE;
+     *rval = OBJECT_TO_JSVAL(arrayobj);
+ 
+     if (argc == 0) {
+         v = STRING_TO_JSVAL(str);
+         ok = JS_SetElement(cx, arrayobj, 0, &v);
+     } else {
+ #if JS_HAS_REGEXPS
+         if (JSVAL_IS_REGEXP(cx, argv[0])) {
+             re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
+             sep = &tmp;
+ 
+             /* Set a magic value so we can detect a successful re match. */
+             sep->chars = NULL;
+         } else
+ #endif
+         {
+             JSString *str2 = js_ValueToString(cx, argv[0]);
+             if (!str2)
+                 return JS_FALSE;
+             argv[0] = STRING_TO_JSVAL(str2);
+ 
+             /*
+              * Point sep at a local copy of str2's header because find_split
+              * will modify sep->length.
+              */
+             tmp.length = JSSTRING_LENGTH(str2);
+             tmp.chars = JSSTRING_CHARS(str2);
+             sep = &tmp;
+             re = NULL;
+         }
+ 
+         /* Use the second argument as the split limit, if given. */
+         limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]);
+         limit = 0; /* Avoid warning. */
+         if (limited) {
+             if (!js_ValueToNumber(cx, argv[1], &d))
+                 return JS_FALSE;
+ 
+             /* Clamp limit between 0 and 1 + string length. */
+             if (!js_DoubleToECMAUint32(cx, d, &limit))
+                 return JS_FALSE;
+             if (limit > JSSTRING_LENGTH(str))
+                 limit = 1 + JSSTRING_LENGTH(str);
+         }
+ 
+         len = i = 0;
+         while ((j = find_split(cx, str, re, &i, sep)) >= 0) {
+             if (limited && len >= limit)
+                 break;
+             sub = js_NewDependentString(cx, str, i, (size_t)(j - i), 0);
+             if (!sub)
+                 return JS_FALSE;
+             v = STRING_TO_JSVAL(sub);
+             if (!JS_SetElement(cx, arrayobj, len, &v))
+                 return JS_FALSE;
+             len++;
+ #if JS_HAS_REGEXPS
+             /*
+              * Imitate perl's feature of including parenthesized substrings
+              * that matched part of the delimiter in the new array, after the
+              * split substring that was delimited.
+              */
+             if (re && sep->chars) {
+                 uintN num;
+                 JSSubString *parsub;
+ 
+                 for (num = 0; num < cx->regExpStatics.parenCount; num++) {
+                     if (limited && len >= limit)
+                         break;
+                     parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
+                     sub = js_NewStringCopyN(cx, parsub->chars, parsub->length,
+                                             0);
+                     if (!sub)
+                         return JS_FALSE;
+                     v = STRING_TO_JSVAL(sub);
+                     if (!JS_SetElement(cx, arrayobj, len, &v))
+                         return JS_FALSE;
+                     len++;
+                 }
+                 sep->chars = NULL;
+             }
+ #endif
+             i = j + sep->length;
+             if (!JS_VERSION_IS_ECMA(cx)) {
+                 /*
+                  * Deviate from ECMA to imitate Perl, which omits a final
+                  * split unless a limit argument is given and big enough.
+                  */
+                 if (!limited && (size_t)i == JSSTRING_LENGTH(str))
+                     break;
+             }
+         }
+         ok = (j != -2);
+     }
+     return ok;
+ }
+ 
+ #if JS_HAS_PERL_SUBSTR
+ static JSBool
+ str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+     jsdouble d;
+     jsdouble length, begin, end;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc != 0) {
+         if (!js_ValueToNumber(cx, argv[0], &d))
+             return JS_FALSE;
+         length = JSSTRING_LENGTH(str);
+         begin = js_DoubleToInteger(d);
+         if (begin < 0) {
+             begin += length;
+             if (begin < 0)
+                 begin = 0;
+         } else if (begin > length) {
+             begin = length;
+         }
+ 
+         if (argc == 1) {
+             end = length;
+         } else {
+             if (!js_ValueToNumber(cx, argv[1], &d))
+                 return JS_FALSE;
+             end = js_DoubleToInteger(d);
+             if (end < 0)
+                 end = 0;
+             end += begin;
+             if (end > length)
+                 end = length;
+         }
+ 
+         str = js_NewDependentString(cx, str, (size_t)begin,
+                                     (size_t)(end - begin), 0);
+         if (!str)
+             return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ #endif /* JS_HAS_PERL_SUBSTR */
+ 
+ #if JS_HAS_SEQUENCE_OPS
+ /*
+  * Python-esque sequence operations.
+  */
+ static JSBool
+ str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str, *str2;
+     uintN i;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     for (i = 0; i < argc; i++) {
+         str2 = js_ValueToString(cx, argv[i]);
+         if (!str2)
+             return JS_FALSE;
+         argv[i] = STRING_TO_JSVAL(str2);
+ 
+         str = js_ConcatStrings(cx, str, str2);
+         if (!str)
+             return JS_FALSE;
+     }
+ 
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+     jsdouble d;
+     jsdouble length, begin, end;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (argc != 0) {
+         if (!js_ValueToNumber(cx, argv[0], &d))
+             return JS_FALSE;
+         length = JSSTRING_LENGTH(str);
+         begin = js_DoubleToInteger(d);
+         if (begin < 0) {
+             begin += length;
+             if (begin < 0)
+                 begin = 0;
+         } else if (begin > length) {
+             begin = length;
+         }
+ 
+         if (argc == 1) {
+             end = length;
+         } else {
+             if (!js_ValueToNumber(cx, argv[1], &d))
+                 return JS_FALSE;
+             end = js_DoubleToInteger(d);
+             if (end < 0) {
+                 end += length;
+                 if (end < 0)
+                     end = 0;
+             } else if (end > length) {
+                 end = length;
+             }
+             if (end < begin)
+                 end = begin;
+         }
+ 
+         str = js_NewDependentString(cx, str, (size_t)begin,
+                                     (size_t)(end - begin), 0);
+         if (!str)
+             return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ #endif /* JS_HAS_SEQUENCE_OPS */
+ 
+ #if JS_HAS_STR_HTML_HELPERS
+ /*
+  * HTML composition aids.
+  */
+ static JSBool
+ tagify(JSContext *cx, JSObject *obj, jsval *argv,
+        const char *begin, JSString *param, const char *end,
+        jsval *rval)
+ {
+     JSString *str;
+     jschar *tagbuf;
+     size_t beglen, endlen, parlen, taglen;
+     size_t i, j;
+ 
+     str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
+     if (!str)
+         return JS_FALSE;
+     argv[-1] = STRING_TO_JSVAL(str);
+ 
+     if (!end)
+         end = begin;
+ 
+     beglen = strlen(begin);
+     taglen = 1 + beglen + 1;                            /* '<begin' + '>' */
+     parlen = 0; /* Avoid warning. */
+     if (param) {
+         parlen = JSSTRING_LENGTH(param);
+         taglen += 2 + parlen + 1;                       /* '="param"' */
+     }
+     endlen = strlen(end);
+     taglen += JSSTRING_LENGTH(str) + 2 + endlen + 1;    /* 'str</end>' */
+ 
+     tagbuf = (jschar *) JS_malloc(cx, (taglen + 1) * sizeof(jschar));
+     if (!tagbuf)
+         return JS_FALSE;
+ 
+     j = 0;
+     tagbuf[j++] = '<';
+     for (i = 0; i < beglen; i++)
+         tagbuf[j++] = (jschar)begin[i];
+     if (param) {
+         tagbuf[j++] = '=';
+         tagbuf[j++] = '"';
+         js_strncpy(&tagbuf[j], JSSTRING_CHARS(param), parlen);
+         j += parlen;
+         tagbuf[j++] = '"';
+     }
+     tagbuf[j++] = '>';
+     js_strncpy(&tagbuf[j], JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+     j += JSSTRING_LENGTH(str);
+     tagbuf[j++] = '<';
+     tagbuf[j++] = '/';
+     for (i = 0; i < endlen; i++)
+         tagbuf[j++] = (jschar)end[i];
+     tagbuf[j++] = '>';
+     JS_ASSERT(j == taglen);
+     tagbuf[j] = 0;
+ 
+     str = js_NewString(cx, tagbuf, taglen, 0);
+     if (!str) {
+         free((char *)tagbuf);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ tagify_value(JSContext *cx, JSObject *obj, jsval *argv,
+              const char *begin, const char *end,
+              jsval *rval)
+ {
+     JSString *param;
+ 
+     param = js_ValueToString(cx, argv[0]);
+     if (!param)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(param);
+     return tagify(cx, obj, argv, begin, param, end, rval);
+ }
+ 
+ static JSBool
+ str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "b", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "i", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "tt", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify_value(cx, obj, argv, "font size", "font", rval);
+ }
+ 
+ static JSBool
+ str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval)
+ {
+     return tagify_value(cx, obj, argv, "font color", "font", rval);
+ }
+ 
+ static JSBool
+ str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify_value(cx, obj, argv, "a href", "a", rval);
+ }
+ 
+ static JSBool
+ str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify_value(cx, obj, argv, "a name", "a", rval);
+ }
+ 
+ static JSBool
+ str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "strike", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "small", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "big", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "blink", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "sup", NULL, NULL, rval);
+ }
+ 
+ static JSBool
+ str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     return tagify(cx, obj, argv, "sub", NULL, NULL, rval);
+ }
+ #endif /* JS_HAS_STR_HTML_HELPERS */
+ 
+ static JSFunctionSpec string_methods[] = {
+ #if JS_HAS_TOSOURCE
+     {"quote",               str_quote,              0,JSFUN_GENERIC_NATIVE,0},
+     {js_toSource_str,       str_toSource,           0,0,0},
+ #endif
+ 
+     /* Java-like methods. */
+     {js_toString_str,       str_toString,           0,0,0},
+     {js_valueOf_str,        str_valueOf,            0,0,0},
+     {"substring",           str_substring,          2,JSFUN_GENERIC_NATIVE,0},
+     {"toLowerCase",         str_toLowerCase,        0,JSFUN_GENERIC_NATIVE,0},
+     {"toUpperCase",         str_toUpperCase,        0,JSFUN_GENERIC_NATIVE,0},
+     {"charAt",              str_charAt,             1,JSFUN_GENERIC_NATIVE,0},
+     {"charCodeAt",          str_charCodeAt,         1,JSFUN_GENERIC_NATIVE,0},
+     {"indexOf",             str_indexOf,            1,JSFUN_GENERIC_NATIVE,0},
+     {"lastIndexOf",         str_lastIndexOf,        1,JSFUN_GENERIC_NATIVE,0},
+     {"toLocaleLowerCase",   str_toLocaleLowerCase,  0,JSFUN_GENERIC_NATIVE,0},
+     {"toLocaleUpperCase",   str_toLocaleUpperCase,  0,JSFUN_GENERIC_NATIVE,0},
+     {"localeCompare",       str_localeCompare,      1,JSFUN_GENERIC_NATIVE,0},
+ 
+     /* Perl-ish methods (search is actually Python-esque). */
+ #if JS_HAS_REGEXPS
+     {"match",               str_match,              1,JSFUN_GENERIC_NATIVE,2},
+     {"search",              str_search,             1,JSFUN_GENERIC_NATIVE,0},
+     {"replace",             str_replace,            2,JSFUN_GENERIC_NATIVE,0},
+     {"split",               str_split,              2,JSFUN_GENERIC_NATIVE,0},
+ #endif
+ #if JS_HAS_PERL_SUBSTR
+     {"substr",              str_substr,             2,JSFUN_GENERIC_NATIVE,0},
+ #endif
+ 
+     /* Python-esque sequence methods. */
+ #if JS_HAS_SEQUENCE_OPS
+     {"concat",              str_concat,             0,JSFUN_GENERIC_NATIVE,0},
+     {"slice",               str_slice,              0,JSFUN_GENERIC_NATIVE,0},
+ #endif
+ 
+     /* HTML string methods. */
+ #if JS_HAS_STR_HTML_HELPERS
+     {"bold",                str_bold,               0,0,0},
+     {"italics",             str_italics,            0,0,0},
+     {"fixed",               str_fixed,              0,0,0},
+     {"fontsize",            str_fontsize,           1,0,0},
+     {"fontcolor",           str_fontcolor,          1,0,0},
+     {"link",                str_link,               1,0,0},
+     {"anchor",              str_anchor,             1,0,0},
+     {"strike",              str_strike,             0,0,0},
+     {"small",               str_small,              0,0,0},
+     {"big",                 str_big,                0,0,0},
+     {"blink",               str_blink,              0,0,0},
+     {"sup",                 str_sup,                0,0,0},
+     {"sub",                 str_sub,                0,0,0},
+ #endif
+ 
+     {0,0,0,0,0}
+ };
+ 
+ static JSBool
+ String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+     JSString *str;
+ 
+     if (argc > 0) {
+         str = js_ValueToString(cx, argv[0]);
+         if (!str)
+             return JS_FALSE;
+         argv[0] = STRING_TO_JSVAL(str);
+     } else {
+         str = cx->runtime->emptyString;
+     }
+     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
+         *rval = STRING_TO_JSVAL(str);
+         return JS_TRUE;
+     }
+     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                  jsval *rval)
+ {
+     jschar *chars;
+     uintN i;
+     uint16 code;
+     JSString *str;
+ 
+     chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
+     if (!chars)
+         return JS_FALSE;
+     for (i = 0; i < argc; i++) {
+         if (!js_ValueToUint16(cx, argv[i], &code)) {
+             JS_free(cx, chars);
+             return JS_FALSE;
+         }
+         chars[i] = (jschar)code;
+     }
+     chars[i] = 0;
+     str = js_NewString(cx, chars, argc, 0);
+     if (!str) {
+         JS_free(cx, chars);
+         return JS_FALSE;
+     }
+     *rval = STRING_TO_JSVAL(str);
+     return JS_TRUE;
+ }
+ 
+ static JSFunctionSpec string_static_methods[] = {
+     {"fromCharCode",    str_fromCharCode,       1,0,0},
+     {0,0,0,0,0}
+ };
+ 
+ static JSHashTable *deflated_string_cache;
+ #ifdef DEBUG
+ static uint32 deflated_string_cache_bytes;
+ #endif
+ #ifdef JS_THREADSAFE
+ static JSLock *deflated_string_cache_lock;
+ #endif
+ 
+ JSBool
+ js_InitStringGlobals(void)
+ {
+ #ifdef JS_THREADSAFE
+     /* Must come through here once in primordial thread to init safely! */
+     if (!deflated_string_cache_lock) {
+         deflated_string_cache_lock = JS_NEW_LOCK();
+         if (!deflated_string_cache_lock)
+             return JS_FALSE;
+     }
+ #endif
+     return JS_TRUE;
+ }
+ 
+ void
+ js_FreeStringGlobals()
+ {
+     if (deflated_string_cache) {
+         JS_HashTableDestroy(deflated_string_cache);
+         deflated_string_cache = NULL;
+     }
+ #ifdef JS_THREADSAFE
+     if (deflated_string_cache_lock) {
+         JS_DESTROY_LOCK(deflated_string_cache_lock);
+         deflated_string_cache_lock = NULL;
+     }
+ #endif
+ }
+ 
+ JSBool
+ js_InitRuntimeStringState(JSContext *cx)
+ {
+     JSRuntime *rt;
+     JSString *empty;
+     JSAtom *atom;
+ 
+     rt = cx->runtime;
+     JS_ASSERT(!rt->emptyString);
+ 
+     /* Make a permanently locked empty string. */
+     empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
+     if (!empty)
+         return JS_FALSE;
+ 
+     /* Atomize it for scripts that use '' + x to convert x to string. */
+     atom = js_AtomizeString(cx, empty, ATOM_PINNED);
+     if (!atom)
+         return JS_FALSE;
+ 
+     rt->emptyString = empty;
+     rt->atomState.emptyAtom = atom;
+     return JS_TRUE;
+ }
+ 
+ void
+ js_FinishRuntimeStringState(JSContext *cx)
+ {
+     JSRuntime *rt = cx->runtime;
+ 
+     js_UnlockGCThingRT(rt, rt->emptyString);
+     rt->emptyString = NULL;
+ }
+ 
+ JSObject *
+ js_InitStringClass(JSContext *cx, JSObject *obj)
+ {
+     JSObject *proto;
+ 
+     /* Define the escape, unescape functions in the global object. */
+     if (!JS_DefineFunctions(cx, obj, string_functions))
+         return NULL;
+ 
+     proto = JS_InitClass(cx, obj, NULL, &js_StringClass, String, 1,
+                          string_props, string_methods,
+                          NULL, string_static_methods);
+     if (!proto)
+         return NULL;
+     OBJ_SET_SLOT(cx, proto, JSSLOT_PRIVATE,
+                  STRING_TO_JSVAL(cx->runtime->emptyString));
+     return proto;
+ }
+ 
+ JSString *
+ js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
+ {
+     JSString *str;
+ 
+     if (length > JSSTRING_LENGTH_MASK) {
+         JS_ReportOutOfMemory(cx);
+         return NULL;
+     }
+ 
+     str = (JSString *) js_NewGCThing(cx, gcflag | GCX_STRING, sizeof(JSString));
+     if (!str)
+         return NULL;
+     str->length = length;
+     str->chars = chars;
+ #ifdef DEBUG
+   {
+     JSRuntime *rt = cx->runtime;
+     JS_RUNTIME_METER(rt, liveStrings);
+     JS_RUNTIME_METER(rt, totalStrings);
+     JS_LOCK_RUNTIME_VOID(rt,
+         (rt->lengthSum += (double)length,
+          rt->lengthSquaredSum += (double)length * (double)length));
+   }
+ #endif
+     return str;
+ }
+ 
+ JSString *
+ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
+                       size_t length, uintN gcflag)
+ {
+     JSDependentString *ds;
+ 
+     if (length == 0)
+         return cx->runtime->emptyString;
+ 
+     if (start == 0 && length == JSSTRING_LENGTH(base))
+         return base;
+ 
+     if (start > JSSTRDEP_START_MASK ||
+         (start != 0 && length > JSSTRDEP_LENGTH_MASK)) {
+         return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length,
+                                  gcflag);
+     }
+ 
+     ds = (JSDependentString *)
+          js_NewGCThing(cx, gcflag | GCX_MUTABLE_STRING, sizeof(JSString));
+     if (!ds)
+         return NULL;
+     if (start == 0) {
+         JSPREFIX_SET_LENGTH(ds, length);
+         JSPREFIX_SET_BASE(ds, base);
+     } else {
+         JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
+         JSSTRDEP_SET_BASE(ds, base);
+     }
+ #ifdef DEBUG
+   {
+     JSRuntime *rt = cx->runtime;
+     JS_RUNTIME_METER(rt, liveDependentStrings);
+     JS_RUNTIME_METER(rt, totalDependentStrings);
+     JS_RUNTIME_METER(rt, liveStrings);
+     JS_RUNTIME_METER(rt, totalStrings);
+     JS_LOCK_RUNTIME_VOID(rt,
+         (rt->strdepLengthSum += (double)length,
+          rt->strdepLengthSquaredSum += (double)length * (double)length));
+     JS_LOCK_RUNTIME_VOID(rt,
+         (rt->lengthSum += (double)length,
+          rt->lengthSquaredSum += (double)length * (double)length));
+   }
+ #endif
+     return (JSString *)ds;
+ }
+ 
+ #ifdef DEBUG
+ #include <math.h>
+ 
+ void printJSStringStats(JSRuntime *rt) {
+     double mean = 0., var = 0., sigma = 0.;
+     jsrefcount count = rt->totalStrings;
+     if (count > 0 && rt->lengthSum >= 0) {
+         mean = rt->lengthSum / count;
+         var = count * rt->lengthSquaredSum - rt->lengthSum * rt->lengthSum;
+         if (var < 0.0 || count <= 1)
+             var = 0.0;
+         else
+             var /= count * (count - 1);
+ 
+         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+         sigma = (var != 0.) ? sqrt(var) : 0.;
+     }
+     fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
+             (unsigned long)count, mean, sigma);
+ 
+     mean = var = sigma = 0.;
+     count = rt->totalDependentStrings;
+     if (count > 0 && rt->strdepLengthSum >= 0) {
+         mean = rt->strdepLengthSum / count;
+         var = count * rt->strdepLengthSquaredSum
+             - rt->strdepLengthSum * rt->strdepLengthSum;
+         if (var < 0.0 || count <= 1)
+             var = 0.0;
+         else
+             var /= count * (count - 1);
+ 
+         /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
+         sigma = (var != 0.) ? sqrt(var) : 0.;
+     }
+     fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
+             (unsigned long)count, mean, sigma);
+ }
+ #endif
+ 
+ JSString *
+ js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag)
+ {
+     jschar *news;
+     JSString *str;
+ 
+     news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar));
+     if (!news)
+         return NULL;
+     js_strncpy(news, s, n);
+     news[n] = 0;
+     str = js_NewString(cx, news, n, gcflag);
+     if (!str)
+         JS_free(cx, news);
+     return str;
+ }
+ 
+ JSString *
+ js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag)
+ {
+     size_t n, m;
+     jschar *news;
+     JSString *str;
+ 
+     n = js_strlen(s);
+     m = (n + 1) * sizeof(jschar);
+     news = (jschar *) JS_malloc(cx, m);
+     if (!news)
+         return NULL;
+     memcpy(news, s, m);
+     str = js_NewString(cx, news, n, gcflag);
+     if (!str)
+         JS_free(cx, news);
+     return str;
+ }
+ 
+ JS_STATIC_DLL_CALLBACK(JSHashNumber)
+ js_hash_string_pointer(const void *key)
+ {
+     return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
+ }
+ 
+ void
+ js_PurgeDeflatedStringCache(JSString *str)
+ {
+     JSHashNumber hash;
+     JSHashEntry *he, **hep;
+ 
+     if (!deflated_string_cache)
+         return;
+ 
+     hash = js_hash_string_pointer(str);
+     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+     hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
+     he = *hep;
+     if (he) {
+ #ifdef DEBUG
+         deflated_string_cache_bytes -= JSSTRING_LENGTH(str);
+ #endif
+         free(he->value);
+         JS_HashTableRawRemove(deflated_string_cache, hep, he);
+     }
+     JS_RELEASE_LOCK(deflated_string_cache_lock);
+ }
+ 
+ void
+ js_FinalizeString(JSContext *cx, JSString *str)
+ {
+     js_FinalizeStringRT(cx->runtime, str);
+ }
+ 
+ void
+ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
+ {
+     JSBool valid;
+ 
+     JS_RUNTIME_UNMETER(rt, liveStrings);
+     if (JSSTRING_IS_DEPENDENT(str)) {
+         /* If JSSTRFLAG_DEPENDENT is set, this string must be valid. */
+         JS_ASSERT(JSSTRDEP_BASE(str));
+         JS_RUNTIME_UNMETER(rt, liveDependentStrings);
+         valid = JS_TRUE;
+     } else {
+         /* A stillborn string has null chars, so is not valid. */
+         valid = (str->chars != NULL);
+         if (valid)
+             free(str->chars);
+     }
+     if (valid) {
+         js_PurgeDeflatedStringCache(str);
+         str->chars = NULL;
+     }
+     str->length = 0;
+ }
+ 
+ JSObject *
+ js_StringToObject(JSContext *cx, JSString *str)
+ {
+     JSObject *obj;
+ 
+     obj = js_NewObject(cx, &js_StringClass, NULL, NULL);
+     if (!obj)
+         return NULL;
+     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
+     return obj;
+ }
+ 
+ JS_FRIEND_API(const char *)
+ js_ValueToPrintableString(JSContext *cx, jsval v)
+ {
+     JSString *str;
+     const char *bytes;
+ 
+     str = js_ValueToString(cx, v);
+     if (!str)
+         return NULL;
+     str = js_QuoteString(cx, str, 0);
+     if (!str)
+         return NULL;
+     bytes = js_GetStringBytes(str);
+     if (!bytes)
+         JS_ReportOutOfMemory(cx);
+     return bytes;
+ }
+ 
+ JSString *
+ js_ValueToString(JSContext *cx, jsval v)
+ {
+     JSObject *obj;
+     JSString *str;
+ 
+     if (JSVAL_IS_OBJECT(v)) {
+         obj = JSVAL_TO_OBJECT(v);
+         if (!obj)
+             return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
+         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
+             return NULL;
+     }
+     if (JSVAL_IS_STRING(v)) {
+         str = JSVAL_TO_STRING(v);
+     } else if (JSVAL_IS_INT(v)) {
+         str = js_NumberToString(cx, JSVAL_TO_INT(v));
+     } else if (JSVAL_IS_DOUBLE(v)) {
+         str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v));
+     } else if (JSVAL_IS_BOOLEAN(v)) {
+         str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v));
+     } else {
+         str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+     }
+     return str;
+ }
+ 
+ JSString *
+ js_ValueToSource(JSContext *cx, jsval v)
+ {
+     if (JSVAL_IS_STRING(v))
+         return js_QuoteString(cx, JSVAL_TO_STRING(v), '"');
+     if (JSVAL_IS_PRIMITIVE(v)) {
+         /* Special case to preserve negative zero, _contra_ toString. */
+         if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) {
+             /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
+             static const jschar js_negzero_ucNstr[] = {'-', '0'};
+ 
+             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2, 0);
+         }
+     } else {
+         if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v),
+                           cx->runtime->atomState.toSourceAtom,
+                           0, NULL, &v)) {
+             return NULL;
+         }
+     }
+     return js_ValueToString(cx, v);
+ }
+ 
+ JSHashNumber
+ js_HashString(JSString *str)
+ {
+     JSHashNumber h;
+     const jschar *s;
+     size_t n;
+ 
+     h = 0;
+     for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
+         h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
+     return h;
+ }
+ 
+ intN
+ js_CompareStrings(JSString *str1, JSString *str2)
+ {
+     size_t l1, l2, n, i;
+     const jschar *s1, *s2;
+     intN cmp;
+ 
+     l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
+     s1 = JSSTRING_CHARS(str1),  s2 = JSSTRING_CHARS(str2);
+     n = JS_MIN(l1, l2);
+     for (i = 0; i < n; i++) {
+         cmp = s1[i] - s2[i];
+         if (cmp != 0)
+             return cmp;
+     }
+     return (intN)(l1 - l2);
+ }
+ 
+ size_t
+ js_strlen(const jschar *s)
+ {
+     const jschar *t;
+ 
+     for (t = s; *t != 0; t++)
+         continue;
+     return (size_t)(t - s);
+ }
+ 
+ jschar *
+ js_strchr(const jschar *s, jschar c)
+ {
+     while (*s != 0) {
+         if (*s == c)
+             return (jschar *)s;
+         s++;
+     }
+     return NULL;
+ }
+ 
+ jschar *
+ js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
+ {
+     while (s < limit) {
+         if (*s == c)
+             return (jschar *)s;
+         s++;
+     }
+     return NULL;
+ }
+ 
+ const jschar *
+ js_SkipWhiteSpace(const jschar *s)
+ {
+     /* JS_ISSPACE is false on a null. */
+     while (JS_ISSPACE(*s))
+         s++;
+     return s;
+ }
+ 
+ #ifdef JS_C_STRINGS_ARE_UTF8
+ 
+ jschar *
+ js_InflateString(JSContext *cx, const char *bytes, size_t *length)
+ {
+     jschar *chars = NULL;
+     size_t dstlen = 0;
+ 
+     if (!js_InflateStringToBuffer(cx, bytes, *length, NULL, &dstlen))
+         return NULL;
+     chars = (jschar *) JS_malloc(cx, (dstlen + 1) * sizeof (jschar));
+     if (!chars)
+         return NULL;
+     js_InflateStringToBuffer(cx, bytes, *length, chars, &dstlen);
+     chars [dstlen] = 0;
+     *length = dstlen;
+     return chars;
+ }
+ 
+ /*
+  * May be called with null cx by js_GetStringBytes, see below.
+  */
+ char *
+ js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
+ {
+     size_t size = 0;
+     char *bytes = NULL;
+     if (!js_DeflateStringToBuffer (cx, chars, length, NULL, &size))
+         return NULL;
+     bytes = (char *) (cx ? JS_malloc(cx, size+1) : malloc(size+1));
+     if (!bytes)
+         return NULL;
+     js_DeflateStringToBuffer (cx, chars, length, bytes, &size);
+     bytes [size] = 0;
+     return bytes;
+ }
+ 
+ JSBool
+ js_DeflateStringToBuffer(JSContext *cx, const jschar* src, size_t srclen, char* dst, size_t* dstlenp)
+ {
+     size_t i, utf8Len, dstlen = *dstlenp, origDstlen = dstlen;
+     jschar c, c2;
+     uint32 v;
+     uint8 utf8buf[6];
+ 
+     if (!dst)
+         dstlen = origDstlen = (size_t) -1;
+ 
+     while (srclen) {
+         c = *src++;
+         srclen--;
+         if ((c >= 0xDC00) && (c <= 0xDFFF))
+             goto badSurrogate;
+         if (c < 0xD800 || c > 0xDBFF) {
+             v = c;
+         } else {
+             if (srclen < 1)
+                 goto bufferTooSmall;
+             c2 = *src++;
+             srclen--;
+             if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
+                 c = c2;
+                 goto badSurrogate;
+             }
+             v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
+         }
+         if (v < 0x0080) {
+             // no encoding necessary - performance hack
+             if (!dstlen)
+                 goto bufferTooSmall;
+             if (dst)
+                 *dst++ = (char) v;
+             utf8Len = 1;
+         } else {
+             utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
+             if (utf8Len > dstlen)
+                 goto bufferTooSmall;
+             if (dst) {
+                 for (i = 0; i < utf8Len; i++)
+                     *dst++ = (char) utf8buf [i];
+             }
+         }
+         dstlen -= utf8Len;
+     }
+     *dstlenp = (origDstlen - dstlen);
+     return JS_TRUE;
+ 
+ badSurrogate:
+     *dstlenp = (origDstlen - dstlen);
+     if (cx) {
+         char buffer [10];
+         JS_snprintf (buffer, 10, "0x%x", c);
+         JS_ReportErrorFlagsAndNumber(cx,
+                                 JSREPORT_ERROR,
+                                 js_GetErrorMessage, NULL,
+                                 JSMSG_BAD_SURROGATE_CHAR,
+                                 buffer);
+     }
+     return JS_FALSE;
+ 
+ bufferTooSmall:
+     *dstlenp = (origDstlen - dstlen);
+     if (cx)
+         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
+     return JS_FALSE;
+ }
+ 
+ JSBool
+ js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, jschar* dst, size_t* dstlenp)
+ {
+     uint32 v;
+     size_t offset = 0, j, n, dstlen = *dstlenp, origDstlen = dstlen;
+ 
+     if (!dst)
+         dstlen = origDstlen = (size_t) -1;
+ 
+     while (srclen) {
+         v = (uint8) *src;
+         n = 1;
+         if (v & 0x80) {
+             while (v & (0x80 >> n))
+                 n++;
+             if (n > srclen)
+                 goto bufferTooSmall;
+             if (n == 1 || n > 6)
+                 goto badCharacter;
+             for (j = 1; j < n; j++) {
+                 if ((src [j] & 0xC0) != 0x80)
+                     goto badCharacter;
+             }
+             v = Utf8ToOneUcs4Char(src, n);
+             if (v >= 0x10000) {
+                 v -= 0x10000;
+                 if (v > 0xFFFFF || dstlen < 2) {
+                     *dstlenp = (origDstlen - dstlen);
+                     if (cx) {
+                         char buffer [10];
+                         JS_snprintf (buffer, 10, "0x%x", v + 0x10000);
+                         JS_ReportErrorFlagsAndNumber(cx,
+                                                 JSREPORT_ERROR,
+                                                 js_GetErrorMessage, NULL,
+                                                 JSMSG_UTF8_CHAR_TOO_LARGE,
+                                                 buffer);
+                     }
+                     return JS_FALSE;
+                 }
+                 if (dstlen < 2)
+                     goto bufferTooSmall;
+                 if (dst) {
+                     *dst++ = (jschar)((v >> 10) + 0xD800);
+                     v = (jschar)((v & 0x3FF) + 0xDC00);
+                 }
+                 dstlen--;
+             }
+         }
+         if (!dstlen)
+             goto bufferTooSmall;
+         if (dst)
+             *dst++ = (jschar) v;
+         dstlen--;
+         offset += n;
+         src += n;
+         srclen -= n;
+     }
+     *dstlenp = (origDstlen - dstlen);
+     return JS_TRUE;
+ 
+ badCharacter:
+     *dstlenp = (origDstlen - dstlen);
+     if (cx) {
+         char buffer [10];
+         JS_snprintf (buffer, 10, "%d", offset);
+         JS_ReportErrorFlagsAndNumber(cx,
+                                 JSREPORT_ERROR,
+                                 js_GetErrorMessage, NULL,
+                                 JSMSG_MALFORMED_UTF8_CHAR,
+                                 buffer);
+     }
+     return JS_FALSE;
+ 
+ bufferTooSmall:
+     *dstlenp = (origDstlen - dstlen);
+     if (cx)
+         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
+     return JS_FALSE;
+ }
+ 
+ #else
+ 
+ JSBool
+ js_InflateStringToBuffer(JSContext* cx, const char *bytes, size_t length, jschar *chars, size_t* charsLength)
+ {
+     size_t i;
+ 
+     if (length > *charsLength) {
+         for (i = 0; i < *charsLength; i++)
+             chars[i] = (unsigned char) bytes[i];
+         if (cx)
+             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
+         return JS_FALSE;
+     }
+     else {
+         for (i = 0; i < length; i++)
+             chars[i] = (unsigned char) bytes[i];
+         *charsLength = length;
+         return JS_TRUE;
+     }
+ }
+ 
+ jschar *
+ js_InflateString(JSContext *cx, const char *bytes, size_t *bytesLength)
+ {
+     jschar *chars;
+     size_t i, length = *bytesLength;
+ 
+     chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
+     if (!chars) {
+         *bytesLength = 0;
+         return NULL;
+     }
+     for (i = 0; i < length; i++)
+         chars[i] = (unsigned char) bytes[i];
+     chars [length] = 0;
+     *bytesLength = length;
+     return chars;
+ }
+ 
+ JSBool
+ js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t length, char *bytes, size_t* bytesLength)
+ {
+     size_t i;
+ 
+     if (length > *bytesLength) {
+         for (i = 0; i < *bytesLength; i++)
+             bytes[i] = (char) chars[i];
+         if (cx)
+             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
+         return JS_FALSE;
+     }
+     else {
+         for (i = 0; i < length; i++)
+             bytes[i] = (char) chars[i];
+         *bytesLength = length;
+         return JS_TRUE;
+     }
+ }
+ 
+ /*
+  * May be called with null cx by js_GetStringBytes, see below.
+  */
+ char *
+ js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
+ {
+     size_t i, size;
+     char *bytes;
+ 
+     size = (length + 1) * sizeof(char);
+     bytes = (char *) (cx ? JS_malloc(cx, size) : malloc(size));
+     if (!bytes)
+         return NULL;
+ 
+     for (i = 0; i < length; i++)
+         bytes[i] = (char) chars[i];
+ 
+     bytes [length] = 0;
+     return bytes;
+ }
+ 
+ #endif
+ 
+ static JSHashTable *
+ GetDeflatedStringCache(void)
+ {
+     JSHashTable *cache;
+ 
+     cache = deflated_string_cache;
+     if (!cache) {
+         cache = JS_NewHashTable(8, js_hash_string_pointer,
+                                 JS_CompareValues, JS_CompareValues,
+                                 NULL, NULL);
+         deflated_string_cache = cache;
+     }
+     return cache;
+ }
+ 
+ JSBool
+ js_SetStringBytes(JSString *str, char *bytes, size_t length)
+ {
+     JSHashTable *cache;
+     JSBool ok;
+     JSHashNumber hash;
+     JSHashEntry **hep;
+ 
+     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+ 
+     cache = GetDeflatedStringCache();
+     if (!cache) {
+         ok = JS_FALSE;
+     } else {
+         hash = js_hash_string_pointer(str);
+         hep = JS_HashTableRawLookup(cache, hash, str);
+         JS_ASSERT(*hep == NULL);
+         ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
+ #ifdef DEBUG
+         if (ok)
+             deflated_string_cache_bytes += length;
+ #endif
+     }
+ 
+     JS_RELEASE_LOCK(deflated_string_cache_lock);
+     return ok;
+ }
+ 
+ char *
+ js_GetStringBytes(JSString *str)
+ {
+     JSHashTable *cache;
+     char *bytes;
+     JSHashNumber hash;
+     JSHashEntry *he, **hep;
+ 
+     JS_ACQUIRE_LOCK(deflated_string_cache_lock);
+ 
+     cache = GetDeflatedStringCache();
+     if (!cache) {
+         bytes = NULL;
+     } else {
+         hash = js_hash_string_pointer(str);
+         hep = JS_HashTableRawLookup(cache, hash, str);
+         he = *hep;
+         if (he) {
+             bytes = (char *) he->value;
+ 
+             /* Try to catch failure to JS_ShutDown between runtime epochs. */
+             JS_ASSERT((*bytes == '\0' && JSSTRING_LENGTH(str) == 0) ||
+                       *bytes == (char) JSSTRING_CHARS(str)[0]);
+         } else {
+             bytes = js_DeflateString(NULL, JSSTRING_CHARS(str),
+                                            JSSTRING_LENGTH(str));
+             if (bytes) {
+                 if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
+ #ifdef DEBUG
+                     deflated_string_cache_bytes += JSSTRING_LENGTH(str);
+ #endif
+                 } else {
+                     free(bytes);
+                     bytes = NULL;
+                 }
+             }
+         }
+     }
+ 
+     JS_RELEASE_LOCK(deflated_string_cache_lock);
+     return bytes;
+ }
+ 
+ /*
+  * From java.lang.Character.java:
+  *
+  * The character properties are currently encoded into 32 bits in the
+  * following manner:
+  *
+  * 10 bits      signed offset used for converting case
+  *  1 bit       if 1, adding the signed offset converts the character to
+  *              lowercase
+  *  1 bit       if 1, subtracting the signed offset converts the character to
+  *              uppercase
+  *  1 bit       if 1, character has a titlecase equivalent (possibly itself)
+  *  3 bits      0  may not be part of an identifier
+  *              1  ignorable control; may continue a Unicode identifier or JS
+  *                 identifier
+  *              2  may continue a JS identifier but not a Unicode identifier
+  *                 (unused)
+  *              3  may continue a Unicode identifier or JS identifier
+  *              4  is a JS whitespace character
+  *              5  may start or continue a JS identifier;
+  *                 may continue but not start a Unicode identifier (_)
+  *              6  may start or continue a JS identifier but not a Unicode
+  *                 identifier ($)
+  *              7  may start or continue a Unicode identifier or JS identifier
+  *              Thus:
+  *                 5, 6, 7 may start a JS identifier
+  *                 1, 2, 3, 5, 6, 7 may continue a JS identifier
+  *                 7 may start a Unicode identifier
+  *                 1, 3, 5, 7 may continue a Unicode identifier
+  *                 1 is ignorable within an identifier
+  *                 4 is JS whitespace
+  *  2 bits      0  this character has no numeric property
+  *              1  adding the digit offset to the character code and then
+  *                 masking with 0x1F will produce the desired numeric value
+  *              2  this character has a "strange" numeric value
+  *              3  a JS supradecimal digit: adding the digit offset to the
+  *                 character code, then masking with 0x1F, then adding 10
+  *                 will produce the desired numeric value
+  *  5 bits      digit offset
+  *  1 bit       XML 1.0 name start character
+  *  1 bit       XML 1.0 name character
+  *  2 bits      reserved for future use
+  *  5 bits      character type
+  */
+ 
+ /* The X table has 1024 entries for a total of 1024 bytes. */
+ 
+ const uint8 js_X[] = {
+   0,   1,   2,   3,   4,   5,   6,   7,  /*  0x0000 */
+   8,   9,  10,  11,  12,  13,  14,  15,  /*  0x0200 */
+  16,  17,  18,  19,  20,  21,  22,  23,  /*  0x0400 */
+  24,  25,  26,  27,  28,  28,  28,  28,  /*  0x0600 */
+  28,  28,  28,  28,  29,  30,  31,  32,  /*  0x0800 */
+  33,  34,  35,  36,  37,  38,  39,  40,  /*  0x0A00 */
+  41,  42,  43,  44,  45,  46,  28,  28,  /*  0x0C00 */
+  47,  48,  49,  50,  51,  52,  53,  28,  /*  0x0E00 */
+  28,  28,  54,  55,  56,  57,  58,  59,  /*  0x1000 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1200 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1400 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1600 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1800 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1A00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x1C00 */
+  60,  60,  61,  62,  63,  64,  65,  66,  /*  0x1E00 */
+  67,  68,  69,  70,  71,  72,  73,  74,  /*  0x2000 */
+  75,  75,  75,  76,  77,  78,  28,  28,  /*  0x2200 */
+  79,  80,  81,  82,  83,  83,  84,  85,  /*  0x2400 */
+  86,  85,  28,  28,  87,  88,  89,  28,  /*  0x2600 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2800 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2A00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2C00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x2E00 */
+  90,  91,  92,  93,  94,  56,  95,  28,  /*  0x3000 */
+  96,  97,  98,  99,  83, 100,  83, 101,  /*  0x3200 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3400 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3600 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3800 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3A00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3C00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x3E00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4000 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4200 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4400 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4600 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4800 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4A00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0x4C00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x4E00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5A00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5C00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x5E00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6A00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6C00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x6E00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7A00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7C00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x7E00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8A00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8C00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x8E00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9A00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0x9C00 */
+  56,  56,  56,  56,  56,  56, 102,  28,  /*  0x9E00 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA000 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA200 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA400 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA600 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xA800 */
+  28,  28,  28,  28,  28,  28,  28,  28,  /*  0xAA00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAC00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xAE00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xB800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBA00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBC00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xBE00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC400 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC600 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xC800 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCA00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCC00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xCE00 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD000 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD200 */
+  56,  56,  56,  56,  56,  56,  56,  56,  /*  0xD400 */
+  56,  56,  56,  56,  56,  56, 103,  28,  /*  0xD600 */
+ 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xD800 */
+ 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDA00 */
+ 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDC00 */
+ 104, 104, 104, 104, 104, 104, 104, 104,  /*  0xDE00 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE000 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE200 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE400 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE600 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xE800 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEA00 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEC00 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xEE00 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF000 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF200 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF400 */
+ 105, 105, 105, 105, 105, 105, 105, 105,  /*  0xF600 */
+ 105, 105, 105, 105,  56,  56,  56,  56,  /*  0xF800 */
+ 106,  28,  28,  28, 107, 108, 109, 110,  /*  0xFA00 */
+  56,  56,  56,  56, 111, 112, 113, 114,  /*  0xFC00 */
+ 115, 116,  56, 117, 118, 119, 120, 121   /*  0xFE00 */
+ };
+ 
+ /* The Y table has 7808 entries for a total of 7808 bytes. */
+ 
+ const uint8 js_Y[] = {
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
+   0,   1,   1,   1,   1,   1,   0,   0,  /*    0 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    0 */
+   2,   3,   3,   3,   4,   3,   3,   3,  /*    0 */
+   5,   6,   3,   7,   3,   8,   3,   3,  /*    0 */
+   9,   9,   9,   9,   9,   9,   9,   9,  /*    0 */
+   9,   9,   3,   3,   7,   7,   7,   3,  /*    0 */
+   3,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
+  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
+  10,  10,  10,  10,  10,  10,  10,  10,  /*    1 */
+  10,  10,  10,   5,   3,   6,  11,  12,  /*    1 */
+  11,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
+  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
+  13,  13,  13,  13,  13,  13,  13,  13,  /*    1 */
+  13,  13,  13,   5,   7,   6,   7,   0,  /*    1 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
+   0,   0,   0,   0,   0,   0,   0,   0,  /*    2 */
+   2,   3,   4,   4,   4,   4,  15,  15,  /*    2 */
+  11,  15,  16,   5,   7,   8,  15,  11,  /*    2 */
+  15,   7,  17,  17,  11,  16,  15,   3,  /*    2 */
+  11,  18,  16,   6,  19,  19,  19,   3,  /*    2 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*    3 */
+  20,  20,  20,  20,  20,  20,  20,   7,  /*    3 */
+  20,  20,  20,  20,  20,  20,  20,  16,  /*    3 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*    3 */
+  21,  21,  21,  21,  21,  21,  21,   7,  /*    3 */
+  21,  21,  21,  21,  21,  21,  21,  22,  /*    3 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    4 */
+  25,  26,  23,  24,  23,  24,  23,  24,  /*    4 */
+  16,  23,  24,  23,  24,  23,  24,  23,  /*    4 */
+  24,  23,  24,  23,  24,  23,  24,  23,  /*    5 */
+  24,  16,  23,  24,  23,  24,  23,  24,  /*    5 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    5 */
+  27,  23,  24,  23,  24,  23,  24,  28,  /*    5 */
+  16,  29,  23,  24,  23,  24,  30,  23,  /*    6 */
+  24,  31,  31,  23,  24,  16,  32,  32,  /*    6 */
+  33,  23,  24,  31,  34,  16,  35,  36,  /*    6 */
+  23,  24,  16,  16,  35,  37,  16,  38,  /*    6 */
+  23,  24,  23,  24,  23,  24,  38,  23,  /*    6 */
+  24,  39,  40,  16,  23,  24,  39,  23,  /*    6 */
+  24,  41,  41,  23,  24,  23,  24,  42,  /*    6 */
+  23,  24,  16,  40,  23,  24,  40,  40,  /*    6 */
+  40,  40,  40,  40,  43,  44,  45,  43,  /*    7 */
+  44,  45,  43,  44,  45,  23,  24,  23,  /*    7 */
+  24,  23,  24,  23,  24,  23,  24,  23,  /*    7 */
+  24,  23,  24,  23,  24,  16,  23,  24,  /*    7 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    7 */
+  16,  43,  44,  45,  23,  24,  46,  46,  /*    7 */
+  46,  46,  23,  24,  23,  24,  23,  24,  /*    7 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    8 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*    9 */
+  16,  16,  16,  47,  48,  16,  49,  49,  /*    9 */
+  50,  50,  16,  51,  16,  16,  16,  16,  /*    9 */
+  49,  16,  16,  52,  16,  16,  16,  16,  /*    9 */
+  53,  54,  16,  16,  16,  16,  16,  54,  /*    9 */
+  16,  16,  55,  16,  16,  16,  16,  16,  /*    9 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*    9 */
+  16,  16,  16,  56,  16,  16,  16,  16,  /*   10 */
+  56,  16,  57,  57,  16,  16,  16,  16,  /*   10 */
+  16,  16,  58,  16,  16,  16,  16,  16,  /*   10 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   10 */
+  16,  46,  46,  46,  46,  46,  46,  46,  /*   10 */
+  59,  59,  59,  59,  59,  59,  59,  59,  /*   10 */
+  59,  11,  11,  59,  59,  59,  59,  59,  /*   10 */
+  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
+  11,  11,  11,  11,  11,  11,  11,  11,  /*   11 */
+  59,  59,  11,  11,  11,  11,  11,  11,  /*   11 */
+  11,  11,  11,  11,  11,  11,  11,  46,  /*   11 */
+  59,  59,  59,  59,  59,  11,  11,  11,  /*   11 */
+  11,  11,  46,  46,  46,  46,  46,  46,  /*   11 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   11 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   12 */
+  60,  60,  60,  60,  60,  60,  46,  46,  /*   13 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
+  60,  60,  46,  46,  46,  46,  46,  46,  /*   13 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   13 */
+  46,  46,  46,  46,   3,   3,  46,  46,  /*   13 */
+  46,  46,  59,  46,  46,  46,   3,  46,  /*   13 */
+  46,  46,  46,  46,  11,  11,  61,   3,  /*   14 */
+  62,  62,  62,  46,  63,  46,  64,  64,  /*   14 */
+  16,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*   14 */
+  20,  20,  46,  20,  20,  20,  20,  20,  /*   14 */
+  20,  20,  20,  20,  65,  66,  66,  66,  /*   14 */
+  16,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*   14 */
+  21,  21,  16,  21,  21,  21,  21,  21,  /*   15 */
+  21,  21,  21,  21,  67,  68,  68,  46,  /*   15 */
+  69,  70,  38,  38,  38,  71,  72,  46,  /*   15 */
+  46,  46,  38,  46,  38,  46,  38,  46,  /*   15 */
+  38,  46,  23,  24,  23,  24,  23,  24,  /*   15 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   15 */
+  73,  74,  16,  40,  46,  46,  46,  46,  /*   15 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   15 */
+  46,  75,  75,  75,  75,  75,  75,  75,  /*   16 */
+  75,  75,  75,  75,  75,  46,  75,  75,  /*   16 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
+  20,  20,  20,  20,  20,  20,  20,  20,  /*   16 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*   16 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
+  21,  21,  21,  21,  21,  21,  21,  21,  /*   17 */
+  46,  74,  74,  74,  74,  74,  74,  74,  /*   17 */
+  74,  74,  74,  74,  74,  46,  74,  74,  /*   17 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   17 */
+  23,  24,  15,  60,  60,  60,  60,  46,  /*   18 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   18 */
+  40,  23,  24,  23,  24,  46,  46,  23,  /*   19 */
+  24,  46,  46,  23,  24,  46,  46,  46,  /*   19 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   19 */
+  23,  24,  23,  24,  46,  46,  23,  24,  /*   19 */
+  23,  24,  23,  24,  23,  24,  46,  46,  /*   19 */
+  23,  24,  46,  46,  46,  46,  46,  46,  /*   19 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   20 */
+  46,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   20 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   21 */
+  76,  76,  76,  76,  76,  76,  76,  46,  /*   21 */
+  46,  59,   3,   3,   3,   3,   3,   3,  /*   21 */
+  46,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
+  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
+  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
+  77,  77,  77,  77,  77,  77,  77,  77,  /*   21 */
+  77,  77,  77,  77,  77,  77,  77,  16,  /*   22 */
+  46,   3,  46,  46,  46,  46,  46,  46,  /*   22 */
+  46,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
+  60,  60,  46,  60,  60,  60,  60,  60,  /*   22 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   22 */
+  60,  60,  46,  60,  60,  60,   3,  60,  /*   22 */
+   3,  60,  60,   3,  60,  46,  46,  46,  /*   23 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   23 */
+  40,  40,  40,  46,  46,  46,  46,  46,  /*   23 */
+  40,  40,  40,   3,   3,  46,  46,  46,  /*   23 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   23 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
+  46,  46,  46,  46,   3,  46,  46,  46,  /*   24 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   24 */
+  46,  46,  46,   3,  46,  46,  46,   3,  /*   24 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   24 */
+  40,  40,  40,  46,  46,  46,  46,  46,  /*   24 */
+  59,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
+  40,  40,  40,  60,  60,  60,  60,  60,  /*   25 */
+  60,  60,  60,  46,  46,  46,  46,  46,  /*   25 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   25 */
+  78,  78,  78,  78,  78,  78,  78,  78,  /*   25 */
+  78,  78,   3,   3,   3,   3,  46,  46,  /*   25 */
+  60,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   25 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   26 */
+  46,  46,  40,  40,  40,  40,  40,  46,  /*   26 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   27 */
+  40,  40,  40,  40,  40,  40,  40,  46,  /*   27 */
+  40,  40,  40,  40,   3,  40,  60,  60,  /*   27 */
+  60,  60,  60,  60,  60,  79,  79,  60,  /*   27 */
+  60,  60,  60,  60,  60,  59,  59,  60,  /*   27 */
+  60,  15,  60,  60,  60,  60,  46,  46,  /*   27 */
+   9,   9,   9,   9,   9,   9,   9,   9,  /*   27 */
+   9,   9,  46,  46,  46,  46,  46,  46,  /*   27 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   28 */
+  46,  60,  60,  80,  46,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   29 */
+  40,  40,  46,  46,  60,  40,  80,  80,  /*   29 */
+  80,  60,  60,  60,  60,  60,  60,  60,  /*   30 */
+  60,  80,  80,  80,  80,  60,  46,  46,  /*   30 */
+  15,  60,  60,  60,  60,  46,  46,  46,  /*   30 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   30 */
+  40,  40,  60,  60,   3,   3,  81,  81,  /*   30 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   30 */
+   3,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   30 */
+  46,  60,  80,  80,  46,  40,  40,  40,  /*   31 */
+  40,  40,  40,  40,  40,  46,  46,  40,  /*   31 */
+  40,  46,  46,  40,  40,  40,  40,  40,  /*   31 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   31 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   31 */
+  40,  46,  40,  46,  46,  46,  40,  40,  /*   31 */
+  40,  40,  46,  46,  60,  46,  80,  80,  /*   31 */
+  80,  60,  60,  60,  60,  46,  46,  80,  /*   32 */
+  80,  46,  46,  80,  80,  60,  46,  46,  /*   32 */
+  46,  46,  46,  46,  46,  46,  46,  80,  /*   32 */
+  46,  46,  46,  46,  40,  40,  46,  40,  /*   32 */
+  40,  40,  60,  60,  46,  46,  81,  81,  /*   32 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   32 */
+  40,  40,   4,   4,  82,  82,  82,  82,  /*   32 */
+  19,  83,  15,  46,  46,  46,  46,  46,  /*   32 */
+  46,  46,  60,  46,  46,  40,  40,  40,  /*   33 */
+  40,  40,  40,  46,  46,  46,  46,  40,  /*   33 */
+  40,  46,  46,  40,  40,  40,  40,  40,  /*   33 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   33 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   33 */
+  40,  46,  40,  40,  46,  40,  40,  46,  /*   33 */
+  40,  40,  46,  46,  60,  46,  80,  80,  /*   33 */
+  80,  60,  60,  46,  46,  46,  46,  60,  /*   34 */
+  60,  46,  46,  60,  60,  60,  46,  46,  /*   34 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
+  46,  40,  40,  40,  40,  46,  40,  46,  /*   34 */
+  46,  46,  46,  46,  46,  46,  81,  81,  /*   34 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   34 */
+  60,  60,  40,  40,  40,  46,  46,  46,  /*   34 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   34 */
+  46,  60,  60,  80,  46,  40,  40,  40,  /*   35 */
+  40,  40,  40,  40,  46,  40,  46,  40,  /*   35 */
+  40,  40,  46,  40,  40,  40,  40,  40,  /*   35 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   35 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   35 */
+  40,  46,  40,  40,  46,  40,  40,  40,  /*   35 */
+  40,  40,  46,  46,  60,  40,  80,  80,  /*   35 */
+  80,  60,  60,  60,  60,  60,  46,  60,  /*   36 */
+  60,  80,  46,  80,  80,  60,  46,  46,  /*   36 */
+  15,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
+  40,  46,  46,  46,  46,  46,  81,  81,  /*   36 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   36 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   36 */
+  46,  60,  80,  80,  46,  40,  40,  40,  /*   37 */
+  40,  40,  40,  40,  40,  46,  46,  40,  /*   37 */
+  40,  46,  46,  40,  40,  40,  40,  40,  /*   37 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   37 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   37 */
+  40,  46,  40,  40,  46,  46,  40,  40,  /*   37 */
+  40,  40,  46,  46,  60,  40,  80,  60,  /*   37 */
+  80,  60,  60,  60,  46,  46,  46,  80,  /*   38 */
+  80,  46,  46,  80,  80,  60,  46,  46,  /*   38 */
+  46,  46,  46,  46,  46,  46,  60,  80,  /*   38 */
+  46,  46,  46,  46,  40,  40,  46,  40,  /*   38 */
+  40,  40,  46,  46,  46,  46,  81,  81,  /*   38 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   38 */
+  15,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   38 */
+  46,  46,  60,  80,  46,  40,  40,  40,  /*   39 */
+  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
+  40,  46,  40,  40,  40,  40,  46,  46,  /*   39 */
+  46,  40,  40,  46,  40,  46,  40,  40,  /*   39 */
+  46,  46,  46,  40,  40,  46,  46,  46,  /*   39 */
+  40,  40,  40,  46,  46,  46,  40,  40,  /*   39 */
+  40,  40,  40,  40,  40,  40,  46,  40,  /*   39 */
+  40,  40,  46,  46,  46,  46,  80,  80,  /*   39 */
+  60,  80,  80,  46,  46,  46,  80,  80,  /*   40 */
+  80,  46,  80,  80,  80,  60,  46,  46,  /*   40 */
+  46,  46,  46,  46,  46,  46,  46,  80,  /*   40 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
+  46,  46,  46,  46,  46,  46,  46,  81,  /*   40 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   40 */
+  84,  19,  19,  46,  46,  46,  46,  46,  /*   40 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   40 */
+  46,  80,  80,  80,  46,  40,  40,  40,  /*   41 */
+  40,  40,  40,  40,  40,  46,  40,  40,  /*   41 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   41 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   41 */
+  40,  40,  40,  40,  46,  40,  40,  40,  /*   41 */
+  40,  40,  46,  46,  46,  46,  60,  60,  /*   41 */
+  60,  80,  80,  80,  80,  46,  60,  60,  /*   42 */
+  60,  46,  60,  60,  60,  60,  46,  46,  /*   42 */
+  46,  46,  46,  46,  46,  60,  60,  46,  /*   42 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
+  40,  40,  46,  46,  46,  46,  81,  81,  /*   42 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   42 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   42 */
+  46,  46,  80,  80,  46,  40,  40,  40,  /*   43 */
+  40,  40,  40,  40,  40,  46,  40,  40,  /*   43 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   43 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   43 */
+  40,  40,  40,  40,  46,  40,  40,  40,  /*   43 */
+  40,  40,  46,  46,  46,  46,  80,  60,  /*   43 */
+  80,  80,  80,  80,  80,  46,  60,  80,  /*   44 */
+  80,  46,  80,  80,  60,  60,  46,  46,  /*   44 */
+  46,  46,  46,  46,  46,  80,  80,  46,  /*   44 */
+  46,  46,  46,  46,  46,  46,  40,  46,  /*   44 */
+  40,  40,  46,  46,  46,  46,  81,  81,  /*   44 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   44 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   44 */
+  46,  46,  80,  80,  46,  40,  40,  40,  /*   45 */
+  40,  40,  40,  40,  40,  46,  40,  40,  /*   45 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
+  40,  46,  40,  40,  40,  40,  40,  40,  /*   45 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   45 */
+  40,  40,  46,  46,  46,  46,  80,  80,  /*   45 */
+  80,  60,  60,  60,  46,  46,  80,  80,  /*   46 */
+  80,  46,  80,  80,  80,  60,  46,  46,  /*   46 */
+  46,  46,  46,  46,  46,  46,  46,  80,  /*   46 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
+  40,  40,  46,  46,  46,  46,  81,  81,  /*   46 */
+  81,  81,  81,  81,  81,  81,  81,  81,  /*   46 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   46 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   47 */
+  40,  40,  40,  40,  40,  40,  40,   3,  /*   47 */
+  40,  60,  40,  40,  60,  60,  60,  60,  /*   47 */
+  60,  60,  60,  46,  46,  46,  46,   4,  /*   47 */
+  40,  40,  40,  40,  40,  40,  59,  60,  /*   48 */
+  60,  60,  60,  60,  60,  60,  60,  15,  /*   48 */
+   9,   9,   9,   9,   9,   9,   9,   9,  /*   48 */
+   9,   9,   3,   3,  46,  46,  46,  46,  /*   48 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   48 */
+  46,  40,  40,  46,  40,  46,  46,  40,  /*   49 */
+  40,  46,  40,  46,  46,  40,  46,  46,  /*   49 */
+  46,  46,  46,  46,  40,  40,  40,  40,  /*   49 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   49 */
+  46,  40,  40,  40,  46,  40,  46,  40,  /*   49 */
+  46,  46,  40,  40,  46,  40,  40,   3,  /*   49 */
+  40,  60,  40,  40,  60,  60,  60,  60,  /*   49 */
+  60,  60,  46,  60,  60,  40,  46,  46,  /*   49 */
+  40,  40,  40,  40,  40,  46,  59,  46,  /*   50 */
+  60,  60,  60,  60,  60,  60,  46,  46,  /*   50 */
+   9,   9,   9,   9,   9,   9,   9,   9,  /*   50 */
+   9,   9,  46,  46,  40,  40,  46,  46,  /*   50 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   50 */
+  15,  15,  15,  15,   3,   3,   3,   3,  /*   51 */
+   3,   3,   3,   3,   3,   3,   3,   3,  /*   51 */
+   3,   3,   3,  15,  15,  15,  15,  15,  /*   51 */
+  60,  60,  15,  15,  15,  15,  15,  15,  /*   51 */
+  78,  78,  78,  78,  78,  78,  78,  78,  /*   51 */
+  78,  78,  85,  85,  85,  85,  85,  85,  /*   51 */
+  85,  85,  85,  85,  15,  60,  15,  60,  /*   51 */
+  15,  60,   5,   6,   5,   6,  80,  80,  /*   51 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   52 */
+  40,  40,  46,  46,  46,  46,  46,  46,  /*   52 */
+  46,  60,  60,  60,  60,  60,  60,  60,  /*   52 */
+  60,  60,  60,  60,  60,  60,  60,  80,  /*   52 */
+  60,  60,  60,  60,  60,   3,  60,  60,  /*   53 */
+  60,  60,  60,  60,  46,  46,  46,  46,  /*   53 */
+  60,  60,  60,  60,  60,  60,  46,  60,  /*   53 */
+  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
+  60,  60,  60,  60,  60,  60,  46,  46,  /*   53 */
+  46,  60,  60,  60,  60,  60,  60,  60,  /*   53 */
+  46,  60,  46,  46,  46,  46,  46,  46,  /*   53 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   54 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
+  76,  76,  76,  76,  76,  76,  76,  76,  /*   54 */
+  76,  76,  76,  76,  76,  76,  46,  46,  /*   55 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   55 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
+  16,  16,  16,  16,  16,  16,  16,  16,  /*   55 */
+  16,  16,  16,  16,  16,  16,  16,  46,  /*   55 */
+  46,  46,  46,   3,  46,  46,  46,  46,  /*   55 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   56 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  46,  46,  46,  46,  46,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   57 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  46,  46,  46,  46,  46,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   58 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   59 */
+  40,  40,  46,  46,  46,  46,  46,  46,  /*   59 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   60 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  16,  16,  /*   61 */
+  16,  16,  16,  16,  46,  46,  46,  46,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   61 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  23,  24,  23,  24,  23,  24,  /*   62 */
+  23,  24,  46,  46,  46,  46,  46,  46,  /*   62 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
+  86,  86,  86,  86,  86,  86,  46,  46,  /*   63 */
+  87,  87,  87,  87,  87,  87,  46,  46,  /*   63 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   63 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   63 */
+  86,  86,  86,  86,  86,  86,  46,  46,  /*   64 */
+  87,  87,  87,  87,  87,  87,  46,  46,  /*   64 */
+  16,  86,  16,  86,  16,  86,  16,  86,  /*   64 */
+  46,  87,  46,  87,  46,  87,  46,  87,  /*   64 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   64 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   64 */
+  88,  88,  89,  89,  89,  89,  90,  90,  /*   64 */
+  91,  91,  92,  92,  93,  93,  46,  46,  /*   64 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
+  86,  86,  86,  86,  86,  86,  86,  86,  /*   65 */
+  87,  87,  87,  87,  87,  87,  87,  87,  /*   65 */
+  86,  86,  16,  94,  16,  46,  16,  16,  /*   65 */
+  87,  87,  95,  95,  96,  11,  38,  11,  /*   65 */
+  11,  11,  16,  94,  16,  46,  16,  16,  /*   66 */
+  97,  97,  97,  97,  96,  11,  11,  11,  /*   66 */
+  86,  86,  16,  16,  46,  46,  16,  16,  /*   66 */
+  87,  87,  98,  98,  46,  11,  11,  11,  /*   66 */
+  86,  86,  16,  16,  16,  99,  16,  16,  /*   66 */
+  87,  87, 100, 100, 101,  11,  11,  11,  /*   66 */
+  46,  46,  16,  94,  16,  46,  16,  16,  /*   66 */
+ 102, 102, 103, 103,  96,  11,  11,  46,  /*   66 */
+   2,   2,   2,   2,   2,   2,   2,   2,  /*   67 */
+   2,   2,   2,   2, 104, 104, 104, 104,  /*   67 */
+   8,   8,   8,   8,   8,   8,   3,   3,  /*   67 */
+   5,   6,   5,   5,   5,   6,   5,   5,  /*   67 */
+   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
+ 105, 106, 104, 104, 104, 104, 104,  46,  /*   67 */
+   3,   3,   3,   3,   3,   3,   3,   3,  /*   67 */
+   3,   5,   6,   3,   3,   3,   3,  12,  /*   67 */
+  12,   3,   3,   3,   7,   5,   6,  46,  /*   68 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   68 */
+  46,  46, 104, 104, 104, 104, 104, 104,  /*   68 */
+  17,  46,  46,  46,  17,  17,  17,  17,  /*   68 */
+  17,  17,   7,   7,   7,   5,   6,  16,  /*   68 */
+ 107, 107, 107, 107, 107, 107, 107, 107,  /*   69 */
+ 107, 107,   7,   7,   7,   5,   6,  46,  /*   69 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
+   4,   4,   4,   4,   4,   4,   4,   4,  /*   69 */
+   4,   4,   4,   4,  46,  46,  46,  46,  /*   69 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   69 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
+  60,  60,  60,  60,  60,  60,  60,  60,  /*   70 */
+  60,  60,  60,  60,  60,  79,  79,  79,  /*   70 */
+  79,  60,  46,  46,  46,  46,  46,  46,  /*   70 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   70 */
+  15,  15,  38,  15,  15,  15,  15,  38,  /*   71 */
+  15,  15,  16,  38,  38,  38,  16,  16,  /*   71 */
+  38,  38,  38,  16,  15,  38,  15,  15,  /*   71 */
+  38,  38,  38,  38,  38,  38,  15,  15,  /*   71 */
+  15,  15,  15,  15,  38,  15,  38,  15,  /*   71 */
+  38,  15,  38,  38,  38,  38,  16,  16,  /*   71 */
+  38,  38,  15,  38,  16,  40,  40,  40,  /*   71 */
+  40,  46,  46,  46,  46,  46,  46,  46,  /*   71 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   72 */
+  46,  46,  46,  19,  19,  19,  19,  19,  /*   72 */
+  19,  19,  19,  19,  19,  19,  19, 108,  /*   72 */
+ 109, 109, 109, 109, 109, 109, 109, 109,  /*   72 */
+ 109, 109, 109, 109, 110, 110, 110, 110,  /*   72 */
+ 111, 111, 111, 111, 111, 111, 111, 111,  /*   72 */
+ 111, 111, 111, 111, 112, 112, 112, 112,  /*   72 */
+ 113, 113, 113,  46,  46,  46,  46,  46,  /*   73 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   73 */
+   7,   7,   7,   7,   7,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   73 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
+  15,  15,   7,  15,   7,  15,  15,  15,  /*   74 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   74 */
+  15,  15,  15,  46,  46,  46,  46,  46,  /*   74 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   74 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   75 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,   7,   7,   7,   7,   7,   7,  /*   76 */
+   7,   7,  46,  46,  46,  46,  46,  46,  /*   76 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   76 */
+  15,  46,  15,  15,  15,  15,  15,  15,  /*   77 */
+   7,   7,   7,   7,  15,  15,  15,  15,  /*   77 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
+   7,   7,  15,  15,  15,  15,  15,  15,  /*   77 */
+  15,   5,   6,  15,  15,  15,  15,  15,  /*   77 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   77 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   78 */
+  15,  15,  15,  46,  46,  46,  46,  46,  /*   78 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   79 */
+  15,  15,  15,  15,  15,  46,  46,  46,  /*   79 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   79 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   80 */
+  15,  15,  15,  46,  46,  46,  46,  46,  /*   80 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   80 */
+ 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
+ 114, 114, 114, 114, 114, 114, 114, 114,  /*   80 */
+ 114, 114, 114, 114,  82,  82,  82,  82,  /*   80 */
+  82,  82,  82,  82,  82,  82,  82,  82,  /*   80 */
+  82,  82,  82,  82,  82,  82,  82,  82,  /*   81 */
+ 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
+ 115, 115, 115, 115, 115, 115, 115, 115,  /*   81 */
+ 115, 115, 115, 115,  15,  15,  15,  15,  /*   81 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   81 */
+  15,  15,  15,  15,  15,  15, 116, 116,  /*   81 */
+ 116, 116, 116, 116, 116, 116, 116, 116,  /*   81 */
+ 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
+ 116, 116, 116, 116, 116, 116, 116, 116,  /*   82 */
+ 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
+ 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
+ 117, 117, 117, 117, 117, 117, 117, 117,  /*   82 */
+ 117, 117, 118,  46,  46,  46,  46,  46,  /*   82 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   82 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   83 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  46,  46,  /*   84 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   84 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   85 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   85 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  46,  46,  46,  46,  /*   86 */
+  46,  46,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   86 */
+  46,  15,  15,  15,  15,  46,  15,  15,  /*   87 */
+  15,  15,  46,  46,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  46,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   87 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
+  15,  15,  15,  15,  46,  15,  46,  15,  /*   88 */
+  15,  15,  15,  46,  46,  46,  15,  46,  /*   88 */
+  15,  15,  15,  15,  15,  15,  15,  46,  /*   88 */
+  46,  15,  15,  15,  15,  15,  15,  15,  /*   88 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   88 */
+  46,  46,  46,  46,  46,  46, 119, 119,  /*   88 */
+ 119, 119, 119, 119, 119, 119, 119, 119,  /*   88 */
+ 114, 114, 114, 114, 114, 114, 114, 114,  /*   89 */
+ 114, 114,  83,  83,  83,  83,  83,  83,  /*   89 */
+  83,  83,  83,  83,  15,  46,  46,  46,  /*   89 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
+  46,  15,  15,  15,  15,  15,  15,  15,  /*   89 */
+  15,  15,  15,  15,  15,  15,  15,  46,  /*   89 */
+   2,   3,   3,   3,  15,  59,   3, 120,  /*   90 */
+   5,   6,   5,   6,   5,   6,   5,   6,  /*   90 */
+   5,   6,  15,  15,   5,   6,   5,   6,  /*   90 */
+   5,   6,   5,   6,   8,   5,   6,   5,  /*   90 */
+  15, 121, 121, 121, 121, 121, 121, 121,  /*   90 */
+ 121, 121,  60,  60,  60,  60,  60,  60,  /*   90 */
+   8,  59,  59,  59,  59,  59,  15,  15,  /*   90 */
+  46,  46,  46,  46,  46,  46,  46,  15,  /*   90 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   91 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  46,  46,  46,  /*   92 */
+  46,  60,  60,  59,  59,  59,  59,  46,  /*   92 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   92 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   93 */
+  40,  40,  40,   3,  59,  59,  59,  46,  /*   93 */
+  46,  46,  46,  46,  46,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  46,  46,  46,  /*   94 */
+  46,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   94 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*   95 */
+  40,  40,  40,  40,  40,  40,  40,  46,  /*   95 */
+  15,  15,  85,  85,  85,  85,  15,  15,  /*   95 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   95 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   95 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  15,  46,  46,  46,  /*   96 */
+  85,  85,  85,  85,  85,  85,  85,  85,  /*   96 */
+  85,  85,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   96 */
+  15,  15,  15,  15,  46,  46,  46,  46,  /*   97 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   97 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   97 */
+  15,  15,  15,  15,  46,  46,  46,  15,  /*   97 */
+ 114, 114, 114, 114, 114, 114, 114, 114,  /*   98 */
+ 114, 114,  15,  15,  15,  15,  15,  15,  /*   98 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   98 */
+  15,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*   98 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  46,  46,  46,  46,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  46,  /*   99 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  46,  /*  100 */
+  46,  46,  46,  15,  15,  15,  15,  15,  /*  100 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  46,  46,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  15,  /*  101 */
+  15,  15,  15,  15,  15,  15,  15,  46,  /*  101 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  102 */
+  40,  40,  40,  40,  40,  40,  46,  46,  /*  102 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  102 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  103 */
+  40,  40,  40,  40,  46,  46,  46,  46,  /*  103 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  103 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 122, 122, 122, 122, 122, 122, 122, 122,  /*  104 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+ 123, 123, 123, 123, 123, 123, 123, 123,  /*  105 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  106 */
+  40,  40,  40,  40,  40,  40,  46,  46,  /*  106 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  106 */
+  16,  16,  16,  16,  16,  16,  16,  46,  /*  107 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  107 */
+  46,  46,  46,  16,  16,  16,  16,  16,  /*  107 */
+  46,  46,  46,  46,  46,  46,  60,  40,  /*  107 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  107 */
+  40,   7,  40,  40,  40,  40,  40,  40,  /*  107 */
+  40,  40,  40,  40,  40,  40,  40,  46,  /*  107 */
+  40,  40,  40,  40,  40,  46,  40,  46,  /*  107 */
+  40,  40,  46,  40,  40,  46,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  108 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  109 */
+  40,  40,  46,  46,  46,  46,  46,  46,  /*  109 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  109 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  110 */
+  46,  46,  46,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  110 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  111 */
+  40,  40,  40,  40,  40,  40,   5,   6,  /*  111 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  112 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  46,  46,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  113 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  114 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  114 */
+  40,  40,  40,  40,  46,  46,  46,  46,  /*  114 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
+  60,  60,  60,  60,  46,  46,  46,  46,  /*  115 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  115 */
+   3,   8,   8,  12,  12,   5,   6,   5,  /*  115 */
+   6,   5,   6,   5,   6,   5,   6,   5,  /*  115 */
+   6,   5,   6,   5,   6,  46,  46,  46,  /*  116 */
+  46,   3,   3,   3,   3,  12,  12,  12,  /*  116 */
+   3,   3,   3,  46,   3,   3,   3,   3,  /*  116 */
+   8,   5,   6,   5,   6,   5,   6,   3,  /*  116 */
+   3,   3,   7,   8,   7,   7,   7,  46,  /*  116 */
+   3,   4,   3,   3,  46,  46,  46,  46,  /*  116 */
+  40,  40,  40,  46,  40,  46,  40,  40,  /*  116 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  116 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  117 */
+  40,  40,  40,  40,  40,  46,  46, 104,  /*  117 */
+  46,   3,   3,   3,   4,   3,   3,   3,  /*  118 */
+   5,   6,   3,   7,   3,   8,   3,   3,  /*  118 */
+   9,   9,   9,   9,   9,   9,   9,   9,  /*  118 */
+   9,   9,   3,   3,   7,   7,   7,   3,  /*  118 */
+   3,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
+  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
+  10,  10,  10,  10,  10,  10,  10,  10,  /*  118 */
+  10,  10,  10,   5,   3,   6,  11,  12,  /*  118 */
+  11,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
+  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
+  13,  13,  13,  13,  13,  13,  13,  13,  /*  119 */
+  13,  13,  13,   5,   7,   6,   7,  46,  /*  119 */
+  46,   3,   5,   6,   3,   3,  40,  40,  /*  119 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
+  59,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  119 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  59,  59,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  40,  /*  120 */
+  40,  40,  40,  40,  40,  40,  40,  46,  /*  120 */
+  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
+  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
+  46,  46,  40,  40,  40,  40,  40,  40,  /*  121 */
+  46,  46,  40,  40,  40,  46,  46,  46,  /*  121 */
+   4,   4,   7,  11,  15,   4,   4,  46,  /*  121 */
+   7,   7,   7,   7,   7,  15,  15,  46,  /*  121 */
+  46,  46,  46,  46,  46,  46,  46,  46,  /*  121 */
+  46,  46,  46,  46,  46,  15,  46,  46   /*  121 */
+ };
+ 
+ /* The A table has 124 entries for a total of 496 bytes. */
+ 
+ const uint32 js_A[] = {
+ 0x0001000F,  /*    0   Cc, ignorable */
+ 0x0004000F,  /*    1   Cc, whitespace */
+ 0x0004000C,  /*    2   Zs, whitespace */
+ 0x00000018,  /*    3   Po */
+ 0x0006001A,  /*    4   Sc, currency */
+ 0x00000015,  /*    5   Ps */
+ 0x00000016,  /*    6   Pe */
+ 0x00000019,  /*    7   Sm */
+ 0x00000014,  /*    8   Pd */
+ 0x00036089,  /*    9   Nd, identifier part, decimal 16 */
+ 0x0827FF81,  /*   10   Lu, hasLower (add 32), identifier start, supradecimal 31 */
+ 0x0000001B,  /*   11   Sk */
+ 0x00050017,  /*   12   Pc, underscore */
+ 0x0817FF82,  /*   13   Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */
+ 0x0000000C,  /*   14   Zs */
+ 0x0000001C,  /*   15   So */
+ 0x00070182,  /*   16   Ll, identifier start */
+ 0x0000600B,  /*   17   No, decimal 16 */
+ 0x0000500B,  /*   18   No, decimal 8 */
+ 0x0000800B,  /*   19   No, strange */
+ 0x08270181,  /*   20   Lu, hasLower (add 32), identifier start */
+ 0x08170182,  /*   21   Ll, hasUpper (subtract 32), identifier start */
+ 0xE1D70182,  /*   22   Ll, hasUpper (subtract -121), identifier start */
+ 0x00670181,  /*   23   Lu, hasLower (add 1), identifier start */
+ 0x00570182,  /*   24   Ll, hasUpper (subtract 1), identifier start */
+ 0xCE670181,  /*   25   Lu, hasLower (add -199), identifier start */
+ 0x3A170182,  /*   26   Ll, hasUpper (subtract 232), identifier start */
+ 0xE1E70181,  /*   27   Lu, hasLower (add -121), identifier start */
+ 0x4B170182,  /*   28   Ll, hasUpper (subtract 300), identifier start */
+ 0x34A70181,  /*   29   Lu, hasLower (add 210), identifier start */
+ 0x33A70181,  /*   30   Lu, hasLower (add 206), identifier start */
+ 0x33670181,  /*   31   Lu, hasLower (add 205), identifier start */
+ 0x32A70181,  /*   32   Lu, hasLower (add 202), identifier start */
+ 0x32E70181,  /*   33   Lu, hasLower (add 203), identifier start */
+ 0x33E70181,  /*   34   Lu, hasLower (add 207), identifier start */
+ 0x34E70181,  /*   35   Lu, hasLower (add 211), identifier start */
+ 0x34670181,  /*   36   Lu, hasLower (add 209), identifier start */
+ 0x35670181,  /*   37   Lu, hasLower (add 213), identifier start */
+ 0x00070181,  /*   38   Lu, identifier start */
+ 0x36A70181,  /*   39   Lu, hasLower (add 218), identifier start */
+ 0x00070185,  /*   40   Lo, identifier start */
+ 0x36670181,  /*   41   Lu, hasLower (add 217), identifier start */
+ 0x36E70181,  /*   42   Lu, hasLower (add 219), identifier start */
+ 0x00AF0181,  /*   43   Lu, hasLower (add 2), hasTitle, identifier start */
+ 0x007F0183,  /*   44   Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */
+ 0x009F0182,  /*   45   Ll, hasUpper (subtract 2), hasTitle, identifier start */
+ 0x00000000,  /*   46   unassigned */
+ 0x34970182,  /*   47   Ll, hasUpper (subtract 210), identifier start */
+ 0x33970182,  /*   48   Ll, hasUpper (subtract 206), identifier start */
+ 0x33570182,  /*   49   Ll, hasUpper (subtract 205), identifier start */
+ 0x32970182,  /*   50   Ll, hasUpper (subtract 202), identifier start */
+ 0x32D70182,  /*   51   Ll, hasUpper (subtract 203), identifier start */
+ 0x33D70182,  /*   52   Ll, hasUpper (subtract 207), identifier start */
+ 0x34570182,  /*   53   Ll, hasUpper (subtract 209), identifier start */
+ 0x34D70182,  /*   54   Ll, hasUpper (subtract 211), identifier start */
+ 0x35570182,  /*   55   Ll, hasUpper (subtract 213), identifier start */
+ 0x36970182,  /*   56   Ll, hasUpper (subtract 218), identifier start */
+ 0x36570182,  /*   57   Ll, hasUpper (subtract 217), identifier start */
+ 0x36D70182,  /*   58   Ll, hasUpper (subtract 219), identifier start */
+ 0x00070084,  /*   59   Lm, identifier start */
+ 0x00030086,  /*   60   Mn, identifier part */
+ 0x09A70181,  /*   61   Lu, hasLower (add 38), identifier start */
+ 0x09670181,  /*   62   Lu, hasLower (add 37), identifier start */
+ 0x10270181,  /*   63   Lu, hasLower (add 64), identifier start */
+ 0x0FE70181,  /*   64   Lu, hasLower (add 63), identifier start */
+ 0x09970182,  /*   65   Ll, hasUpper (subtract 38), identifier start */
+ 0x09570182,  /*   66   Ll, hasUpper (subtract 37), identifier start */
+ 0x10170182,  /*   67   Ll, hasUpper (subtract 64), identifier start */
+ 0x0FD70182,  /*   68   Ll, hasUpper (subtract 63), identifier start */
+ 0x0F970182,  /*   69   Ll, hasUpper (subtract 62), identifier start */
+ 0x0E570182,  /*   70   Ll, hasUpper (subtract 57), identifier start */
+ 0x0BD70182,  /*   71   Ll, hasUpper (subtract 47), identifier start */
+ 0x0D970182,  /*   72   Ll, hasUpper (subtract 54), identifier start */
+ 0x15970182,  /*   73   Ll, hasUpper (subtract 86), identifier start */
+ 0x14170182,  /*   74   Ll, hasUpper (subtract 80), identifier start */
+ 0x14270181,  /*   75   Lu, hasLower (add 80), identifier start */
+ 0x0C270181,  /*   76   Lu, hasLower (add 48), identifier start */
+ 0x0C170182,  /*   77   Ll, hasUpper (subtract 48), identifier start */
+ 0x00034089,  /*   78   Nd, identifier part, decimal 0 */
+ 0x00000087,  /*   79   Me */
+ 0x00030088,  /*   80   Mc, identifier part */
+ 0x00037489,  /*   81   Nd, identifier part, decimal 26 */
+ 0x00005A0B,  /*   82   No, decimal 13 */
+ 0x00006E0B,  /*   83   No, decimal 23 */
+ 0x0000740B,  /*   84   No, decimal 26 */
+ 0x0000000B,  /*   85   No */
+ 0xFE170182,  /*   86   Ll, hasUpper (subtract -8), identifier start */
+ 0xFE270181,  /*   87   Lu, hasLower (add -8), identifier start */
+ 0xED970182,  /*   88   Ll, hasUpper (subtract -74), identifier start */
+ 0xEA970182,  /*   89   Ll, hasUpper (subtract -86), identifier start */
+ 0xE7170182,  /*   90   Ll, hasUpper (subtract -100), identifier start */
+ 0xE0170182,  /*   91   Ll, hasUpper (subtract -128), identifier start */
+ 0xE4170182,  /*   92   Ll, hasUpper (subtract -112), identifier start */
+ 0xE0970182,  /*   93   Ll, hasUpper (subtract -126), identifier start */
+ 0xFDD70182,  /*   94   Ll, hasUpper (subtract -9), identifier start */
+ 0xEDA70181,  /*   95   Lu, hasLower (add -74), identifier start */
+ 0xFDE70181,  /*   96   Lu, hasLower (add -9), identifier start */
+ 0xEAA70181,  /*   97   Lu, hasLower (add -86), identifier start */
+ 0xE7270181,  /*   98   Lu, hasLower (add -100), identifier start */
+ 0xFE570182,  /*   99   Ll, hasUpper (subtract -7), identifier start */
+ 0xE4270181,  /*  100   Lu, hasLower (add -112), identifier start */
+ 0xFE670181,  /*  101   Lu, hasLower (add -7), identifier start */
+ 0xE0270181,  /*  102   Lu, hasLower (add -128), identifier start */
+ 0xE0A70181,  /*  103   Lu, hasLower (add -126), identifier start */
+ 0x00010010,  /*  104   Cf, ignorable */
+ 0x0004000D,  /*  105   Zl, whitespace */
+ 0x0004000E,  /*  106   Zp, whitespace */
+ 0x0000400B,  /*  107   No, decimal 0 */
+ 0x0000440B,  /*  108   No, decimal 2 */
+ 0x0427438A,  /*  109   Nl, hasLower (add 16), identifier start, decimal 1 */
+ 0x0427818A,  /*  110   Nl, hasLower (add 16), identifier start, strange */
+ 0x0417638A,  /*  111   Nl, hasUpper (subtract 16), identifier start, decimal 17 */
+ 0x0417818A,  /*  112   Nl, hasUpper (subtract 16), identifier start, strange */
+ 0x0007818A,  /*  113   Nl, identifier start, strange */
+ 0x0000420B,  /*  114   No, decimal 1 */
+ 0x0000720B,  /*  115   No, decimal 25 */
+ 0x06A0001C,  /*  116   So, hasLower (add 26) */
+ 0x0690001C,  /*  117   So, hasUpper (subtract 26) */
+ 0x00006C0B,  /*  118   No, decimal 22 */
+ 0x0000560B,  /*  119   No, decimal 11 */
+ 0x0007738A,  /*  120   Nl, identifier start, decimal 25 */
+ 0x0007418A,  /*  121   Nl, identifier start, decimal 0 */
+ 0x00000013,  /*  122   Cs */
+ 0x00000012   /*  123   Co */
+ };
+ 
+ const jschar js_uriReservedPlusPound_ucstr[] =
+     {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0};
+ const jschar js_uriUnescaped_ucstr[] =
+     {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+      '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0};
+ 
+ #define URI_CHUNK 64U
+ 
+ /* Concatenate jschars onto an unshared/newborn JSString. */
+ static JSBool
+ AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
+ {
+     size_t total;
+ 
+     JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
+     total = str->length + length + 1;
+     if (!str->chars ||
+         JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
+         total = JS_ROUNDUP(total, URI_CHUNK);
+         str->chars = JS_realloc(cx, str->chars, total * sizeof(jschar));
+         if (!str->chars)
+             return JS_FALSE;
+     }
+     js_strncpy(str->chars + str->length, chars, length);
+     str->length += length;
+     str->chars[str->length] = 0;
+     return JS_TRUE;
+ }
+ 
+ /*
+  * ECMA 3, 15.1.3 URI Handling Function Properties
+  *
+  * The following are implementations of the algorithms
+  * given in the ECMA specification for the hidden functions
+  * 'Encode' and 'Decode'.
+  */
+ static JSBool
+ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
+        const jschar *unescapedSet2, jsval *rval)
+ {
+     size_t length, j, k, L;
+     jschar *chars, c, c2;
+     uint32 v;
+     uint8 utf8buf[6];
+     jschar hexBuf[4];
+     static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
+     JSString *R;
+ 
+     length = JSSTRING_LENGTH(str);
+     if (length == 0) {
+         *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
+         return JS_TRUE;
+     }
+ 
+     R = js_NewString(cx, NULL, 0, 0);
+     if (!R)
+         return JS_FALSE;
+ 
+     hexBuf[0] = '%';
+     hexBuf[3] = 0;
+     chars = JSSTRING_CHARS(str);
+     for (k = 0; k < length; k++) {
+         c = chars[k];
+         if (js_strchr(unescapedSet, c) ||
+             (unescapedSet2 && js_strchr(unescapedSet2, c))) {
+             if (!AddCharsToURI(cx, R, &c, 1))
+                 return JS_FALSE;
+         } else {
+             if ((c >= 0xDC00) && (c <= 0xDFFF)) {
+                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                  JSMSG_BAD_URI, NULL);
+                 return JS_FALSE;
+             }
+             if (c < 0xD800 || c > 0xDBFF) {
+                 v = c;
+             } else {
+                 k++;
+                 if (k == length) {
+                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                      JSMSG_BAD_URI, NULL);
+                     return JS_FALSE;
+                 }
+                 c2 = chars[k];
+                 if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
+                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                      JSMSG_BAD_URI, NULL);
+                     return JS_FALSE;
+                 }
+                 v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
+             }
+             L = js_OneUcs4ToUtf8Char(utf8buf, v);
+             for (j = 0; j < L; j++) {
+                 hexBuf[1] = HexDigits[utf8buf[j] >> 4];
+                 hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
+                 if (!AddCharsToURI(cx, R, hexBuf, 3))
+                     return JS_FALSE;
+             }
+         }
+     }
+ 
+     /*
+      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
+      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
+      * more jschars than it needs.
+      */
+     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
+     if (chars)
+         R->chars = chars;
+     *rval = STRING_TO_JSVAL(R);
+     return JS_TRUE;
+ }
+ 
+ static JSBool
+ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
+ {
+     size_t length, start, k;
+     jschar *chars, c, H;
+     uint32 v;
+     jsuint B;
+     uint8 octets[6];
+     JSString *R;
+     intN j, n;
+ 
+     length = JSSTRING_LENGTH(str);
+     if (length == 0) {
+         *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
+         return JS_TRUE;
+     }
+ 
+     R = js_NewString(cx, NULL, 0, 0);
+     if (!R)
+         return JS_FALSE;
+ 
+     chars = JSSTRING_CHARS(str);
+     for (k = 0; k < length; k++) {
+         c = chars[k];
+         if (c == '%') {
+             start = k;
+             if ((k + 2) >= length)
+                 goto bad;
+             if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
+                 goto bad;
+             B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
+             k += 2;
+             if (!(B & 0x80)) {
+                 c = (jschar)B;
+             } else {
+                 n = 1;
+                 while (B & (0x80 >> n))
+                     n++;
+                 if (n == 1 || n > 6)
+                     goto bad;
+                 octets[0] = (uint8)B;
+                 if (k + 3 * (n - 1) >= length)
+                     goto bad;
+                 for (j = 1; j < n; j++) {
+                     k++;
+                     if (chars[k] != '%')
+                         goto bad;
+                     if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
+                         goto bad;
+                     B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
+                     if ((B & 0xC0) != 0x80)
+                         goto bad;
+                     k += 2;
+                     octets[j] = (char)B;
+                 }
+                 v = Utf8ToOneUcs4Char(octets, n);
+                 if (v >= 0x10000) {
+                     v -= 0x10000;
+                     if (v > 0xFFFFF)
+                         goto bad;
+                     c = (jschar)((v & 0x3FF) + 0xDC00);
+                     H = (jschar)((v >> 10) + 0xD800);
+                     if (!AddCharsToURI(cx, R, &H, 1))
+                         return JS_FALSE;
+                 } else {
+                     c = (jschar)v;
+                 }
+             }
+             if (js_strchr(reservedSet, c)) {
+                 if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
+                     return JS_FALSE;
+             } else {
+                 if (!AddCharsToURI(cx, R, &c, 1))
+                     return JS_FALSE;
+             }
+         } else {
+             if (!AddCharsToURI(cx, R, &c, 1))
+                 return JS_FALSE;
+         }
+     }
+ 
+     /*
+      * Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
+      * don't worry about that case here.  Worst case, R hangs onto URI_CHUNK-1
+      * more jschars than it needs.
+      */
+     chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
+     if (chars)
+         R->chars = chars;
+     *rval = STRING_TO_JSVAL(R);
+     return JS_TRUE;
+ 
+ bad:
+     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
+     return JS_FALSE;
+ }
+ 
+ static JSBool
+ str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+     return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval);
+ }
+ 
+ static JSBool
+ str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                         jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+     return Decode(cx, str, js_empty_ucstr, rval);
+ }
+ 
+ static JSBool
+ str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+               jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+     return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr,
+                   rval);
+ }
+ 
+ static JSBool
+ str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                         jsval *rval)
+ {
+     JSString *str;
+ 
+     str = js_ValueToString(cx, argv[0]);
+     if (!str)
+         return JS_FALSE;
+     argv[0] = STRING_TO_JSVAL(str);
+     return Encode(cx, str, js_uriUnescaped_ucstr, NULL, rval);
+ }
+ 
+ /*
+  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
+  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
+  */
+ int
+ js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char)
+ {
+     int utf8Length = 1;
+ 
+     JS_ASSERT(ucs4Char <= 0x7FFFFFFF);
+     if (ucs4Char < 0x80) {
+         *utf8Buffer = (uint8)ucs4Char;
+     } else {
+         int i;
+         uint32 a = ucs4Char >> 11;
+         utf8Length = 2;
+         while (a) {
+             a >>= 5;
+             utf8Length++;
+         }
+         i = utf8Length;
+         while (--i) {
+             utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80);
+             ucs4Char >>= 6;
+         }
+         *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
+     }
+     return utf8Length;
+ }
+ 
+ /*
+  * Convert a utf8 character sequence into a UCS-4 character and return that
+  * character.  It is assumed that the caller already checked that the sequence
+  * is valid.
+  */
+ static uint32
+ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
+ {
+     uint32 ucs4Char;
+     uint32 minucs4Char;
+     /* from Unicode 3.1, non-shortest form is illegal */
+     static const uint32 minucs4Table[] = {
+         0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
+     };
+ 
+     JS_ASSERT(utf8Length >= 1 && utf8Length <= 6);
+     if (utf8Length == 1) {
+         ucs4Char = *utf8Buffer;
+         JS_ASSERT(!(ucs4Char & 0x80));
+     } else {
+         JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) ==
+                   (0x100 - (1 << (8-utf8Length))));
+         ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
+         minucs4Char = minucs4Table[utf8Length-2];
+         while (--utf8Length) {
+             JS_ASSERT((*utf8Buffer & 0xC0) == 0x80);
+             ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
+         }
+         if (ucs4Char < minucs4Char ||
+             ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) {
+             ucs4Char = 0xFFFD;
+         }
+     }
+     return ucs4Char;
+ }

CVSTrac 2.0.1