PageRenderTime 297ms CodeModel.GetById 105ms app.highlight 172ms RepoModel.GetById 1ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsapi.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 2314 lines | 1863 code | 266 blank | 185 comment | 297 complexity | 1b4b4664355e81ed970caba93e4dbf1d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
   2 * vim: set ts=8 sw=4 et tw=78:
   3 *
   4 * ***** BEGIN LICENSE BLOCK *****
   5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   6 *
   7 * The contents of this file are subject to the Mozilla Public License Version
   8 * 1.1 (the "License"); you may not use this file except in compliance with
   9 * the License. You may obtain a copy of the License at
  10 * http://www.mozilla.org/MPL/
  11 *
  12 * Software distributed under the License is distributed on an "AS IS" basis,
  13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14 * for the specific language governing rights and limitations under the
  15 * License.
  16 *
  17 * The Original Code is Mozilla Communicator client code, released
  18 * March 31, 1998.
  19 *
  20 * The Initial Developer of the Original Code is
  21 * Netscape Communications Corporation.
  22 * Portions created by the Initial Developer are Copyright (C) 1998
  23 * the Initial Developer. All Rights Reserved.
  24 *
  25 * Contributor(s):
  26 *
  27 * Alternatively, the contents of this file may be used under the terms of
  28 * either of the GNU General Public License Version 2 or later (the "GPL"),
  29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30 * in which case the provisions of the GPL or the LGPL are applicable instead
  31 * of those above. If you wish to allow use of your version of this file only
  32 * under the terms of either the GPL or the LGPL, and not to allow others to
  33 * use your version of this file under the terms of the MPL, indicate your
  34 * decision by deleting the provisions above and replace them with the notice
  35 * and other provisions required by the GPL or the LGPL. If you do not delete
  36 * the provisions above, a recipient may use your version of this file under
  37 * the terms of any one of the MPL, the GPL or the LGPL.
  38 *
  39 * ***** END LICENSE BLOCK ***** */
  40
  41/*
  42 * JavaScript API.
  43 */
  44#include "jsstddef.h"
  45#include <ctype.h>
  46#include <stdarg.h>
  47#include <stdlib.h>
  48#include <string.h>
  49#include "jstypes.h"
  50#include "jsarena.h" /* Added by JSIFY */
  51#include "jsutil.h" /* Added by JSIFY */
  52#include "jsclist.h"
  53#include "jsdhash.h"
  54#include "jsprf.h"
  55#include "jsapi.h"
  56#include "jsarray.h"
  57#include "jsatom.h"
  58#include "jsbool.h"
  59#include "jsbuiltins.h"
  60#include "jscntxt.h"
  61#include "jsversion.h"
  62#include "jsdate.h"
  63#include "jsdtoa.h"
  64#include "jsemit.h"
  65#include "jsexn.h"
  66#include "jsfun.h"
  67#include "jsgc.h"
  68#include "jsinterp.h"
  69#include "jsiter.h"
  70#include "jslock.h"
  71#include "jsmath.h"
  72#include "jsnum.h"
  73#include "json.h"
  74#include "jsobj.h"
  75#include "jsopcode.h"
  76#include "jsparse.h"
  77#include "jsregexp.h"
  78#include "jsscan.h"
  79#include "jsscope.h"
  80#include "jsscript.h"
  81#include "jsstr.h"
  82#include "prmjtime.h"
  83#include "jsstaticcheck.h"
  84
  85#if !defined JS_THREADSAFE && defined JS_TRACER
  86#include "jstracer.h"
  87#endif
  88
  89#if JS_HAS_FILE_OBJECT
  90#include "jsfile.h"
  91#endif
  92
  93#if JS_HAS_XML_SUPPORT
  94#include "jsxml.h"
  95#endif
  96
  97#ifdef HAVE_VA_LIST_AS_ARRAY
  98#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
  99#else
 100#define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 101#endif
 102
 103#if defined(JS_THREADSAFE)
 104#define CHECK_REQUEST(cx)                                                   \
 105    JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
 106#else
 107#define CHECK_REQUEST(cx)       ((void)0)
 108#endif
 109
 110JS_PUBLIC_API(int64)
 111JS_Now()
 112{
 113    return PRMJ_Now();
 114}
 115
 116JS_PUBLIC_API(jsval)
 117JS_GetNaNValue(JSContext *cx)
 118{
 119    return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
 120}
 121
 122JS_PUBLIC_API(jsval)
 123JS_GetNegativeInfinityValue(JSContext *cx)
 124{
 125    return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
 126}
 127
 128JS_PUBLIC_API(jsval)
 129JS_GetPositiveInfinityValue(JSContext *cx)
 130{
 131    return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
 132}
 133
 134JS_PUBLIC_API(jsval)
 135JS_GetEmptyStringValue(JSContext *cx)
 136{
 137    return STRING_TO_JSVAL(cx->runtime->emptyString);
 138}
 139
 140static JSBool
 141TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
 142                     jsval **vpp, va_list *app)
 143{
 144    const char *format;
 145    JSArgumentFormatMap *map;
 146
 147    format = *formatp;
 148    for (map = cx->argumentFormatMap; map; map = map->next) {
 149        if (!strncmp(format, map->format, map->length)) {
 150            *formatp = format + map->length;
 151            return map->formatter(cx, format, fromJS, vpp, app);
 152        }
 153    }
 154    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
 155    return JS_FALSE;
 156}
 157
 158JS_PUBLIC_API(JSBool)
 159JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
 160                    ...)
 161{
 162    va_list ap;
 163    JSBool ok;
 164
 165    va_start(ap, format);
 166    ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
 167    va_end(ap);
 168    return ok;
 169}
 170
 171JS_PUBLIC_API(JSBool)
 172JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
 173                      const char *format, va_list ap)
 174{
 175    jsval *sp;
 176    JSBool required;
 177    char c;
 178    JSFunction *fun;
 179    jsdouble d;
 180    JSString *str;
 181    JSObject *obj;
 182
 183    CHECK_REQUEST(cx);
 184    sp = argv;
 185    required = JS_TRUE;
 186    while ((c = *format++) != '\0') {
 187        if (isspace(c))
 188            continue;
 189        if (c == '/') {
 190            required = JS_FALSE;
 191            continue;
 192        }
 193        if (sp == argv + argc) {
 194            if (required) {
 195                fun = js_ValueToFunction(cx, &argv[-2], 0);
 196                if (fun) {
 197                    char numBuf[12];
 198                    JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
 199                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 200                                         JSMSG_MORE_ARGS_NEEDED,
 201                                         JS_GetFunctionName(fun), numBuf,
 202                                         (argc == 1) ? "" : "s");
 203                }
 204                return JS_FALSE;
 205            }
 206            break;
 207        }
 208        switch (c) {
 209          case 'b':
 210            *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
 211            break;
 212          case 'c':
 213            if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
 214                return JS_FALSE;
 215            break;
 216          case 'i':
 217            if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
 218                return JS_FALSE;
 219            break;
 220          case 'u':
 221            if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
 222                return JS_FALSE;
 223            break;
 224          case 'j':
 225            if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
 226                return JS_FALSE;
 227            break;
 228          case 'd':
 229            if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
 230                return JS_FALSE;
 231            break;
 232          case 'I':
 233            if (!JS_ValueToNumber(cx, *sp, &d))
 234                return JS_FALSE;
 235            *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
 236            break;
 237          case 's':
 238          case 'S':
 239          case 'W':
 240            str = js_ValueToString(cx, *sp);
 241            if (!str)
 242                return JS_FALSE;
 243            *sp = STRING_TO_JSVAL(str);
 244            if (c == 's') {
 245                const char *bytes = js_GetStringBytes(cx, str);
 246                if (!bytes)
 247                    return JS_FALSE;
 248                *va_arg(ap, const char **) = bytes;
 249            } else if (c == 'W') {
 250                const jschar *chars = js_GetStringChars(cx, str);
 251                if (!chars)
 252                    return JS_FALSE;
 253                *va_arg(ap, const jschar **) = chars;
 254            } else {
 255                *va_arg(ap, JSString **) = str;
 256            }
 257            break;
 258          case 'o':
 259            if (!js_ValueToObject(cx, *sp, &obj))
 260                return JS_FALSE;
 261            *sp = OBJECT_TO_JSVAL(obj);
 262            *va_arg(ap, JSObject **) = obj;
 263            break;
 264          case 'f':
 265            obj = js_ValueToFunctionObject(cx, sp, 0);
 266            if (!obj)
 267                return JS_FALSE;
 268            *sp = OBJECT_TO_JSVAL(obj);
 269            *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
 270            break;
 271          case 'v':
 272            *va_arg(ap, jsval *) = *sp;
 273            break;
 274          case '*':
 275            break;
 276          default:
 277            format--;
 278            if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
 279                                      JS_ADDRESSOF_VA_LIST(ap))) {
 280                return JS_FALSE;
 281            }
 282            /* NB: the formatter already updated sp, so we continue here. */
 283            continue;
 284        }
 285        sp++;
 286    }
 287    return JS_TRUE;
 288}
 289
 290JS_PUBLIC_API(jsval *)
 291JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
 292{
 293    va_list ap;
 294    jsval *argv;
 295
 296    va_start(ap, format);
 297    argv = JS_PushArgumentsVA(cx, markp, format, ap);
 298    va_end(ap);
 299    return argv;
 300}
 301
 302JS_PUBLIC_API(jsval *)
 303JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
 304{
 305    uintN argc;
 306    jsval *argv, *sp;
 307    char c;
 308    const char *cp;
 309    JSString *str;
 310    JSFunction *fun;
 311    JSStackHeader *sh;
 312
 313    CHECK_REQUEST(cx);
 314    *markp = NULL;
 315    argc = 0;
 316    for (cp = format; (c = *cp) != '\0'; cp++) {
 317        /*
 318         * Count non-space non-star characters as individual jsval arguments.
 319         * This may over-allocate stack, but we'll fix below.
 320         */
 321        if (isspace(c) || c == '*')
 322            continue;
 323        argc++;
 324    }
 325    sp = js_AllocStack(cx, argc, markp);
 326    if (!sp)
 327        return NULL;
 328    argv = sp;
 329    while ((c = *format++) != '\0') {
 330        if (isspace(c) || c == '*')
 331            continue;
 332        switch (c) {
 333          case 'b':
 334            *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
 335            break;
 336          case 'c':
 337            *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
 338            break;
 339          case 'i':
 340          case 'j':
 341            /*
 342             * Use JS_New{Double,Number}Value here and in the next two cases,
 343             * not js_New{Double,Number}InRootedValue, as sp may point to an
 344             * unrooted location.
 345             */
 346            if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
 347                goto bad;
 348            break;
 349          case 'u':
 350            if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
 351                goto bad;
 352            break;
 353          case 'd':
 354          case 'I':
 355            if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
 356                goto bad;
 357            break;
 358          case 's':
 359            str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
 360            if (!str)
 361                goto bad;
 362            *sp = STRING_TO_JSVAL(str);
 363            break;
 364          case 'W':
 365            str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
 366            if (!str)
 367                goto bad;
 368            *sp = STRING_TO_JSVAL(str);
 369            break;
 370          case 'S':
 371            str = va_arg(ap, JSString *);
 372            *sp = STRING_TO_JSVAL(str);
 373            break;
 374          case 'o':
 375            *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
 376            break;
 377          case 'f':
 378            fun = va_arg(ap, JSFunction *);
 379            *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL;
 380            break;
 381          case 'v':
 382            *sp = va_arg(ap, jsval);
 383            break;
 384          default:
 385            format--;
 386            if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
 387                                      JS_ADDRESSOF_VA_LIST(ap))) {
 388                goto bad;
 389            }
 390            /* NB: the formatter already updated sp, so we continue here. */
 391            continue;
 392        }
 393        sp++;
 394    }
 395
 396    /*
 397     * We may have overallocated stack due to a multi-character format code
 398     * handled by a JSArgumentFormatter.  Give back that stack space!
 399     */
 400    JS_ASSERT(sp <= argv + argc);
 401    if (sp < argv + argc) {
 402        /* Return slots not pushed to the current stack arena. */
 403        cx->stackPool.current->avail = (jsuword)sp;
 404
 405        /* Reduce the count of slots the GC will scan in this stack segment. */
 406        sh = cx->stackHeaders;
 407        JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
 408        sh->nslots -= argc - (sp - argv);
 409    }
 410    return argv;
 411
 412bad:
 413    js_FreeStack(cx, *markp);
 414    return NULL;
 415}
 416
 417JS_PUBLIC_API(void)
 418JS_PopArguments(JSContext *cx, void *mark)
 419{
 420    CHECK_REQUEST(cx);
 421    js_FreeStack(cx, mark);
 422}
 423
 424JS_PUBLIC_API(JSBool)
 425JS_AddArgumentFormatter(JSContext *cx, const char *format,
 426                        JSArgumentFormatter formatter)
 427{
 428    size_t length;
 429    JSArgumentFormatMap **mpp, *map;
 430
 431    length = strlen(format);
 432    mpp = &cx->argumentFormatMap;
 433    while ((map = *mpp) != NULL) {
 434        /* Insert before any shorter string to match before prefixes. */
 435        if (map->length < length)
 436            break;
 437        if (map->length == length && !strcmp(map->format, format))
 438            goto out;
 439        mpp = &map->next;
 440    }
 441    map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
 442    if (!map)
 443        return JS_FALSE;
 444    map->format = format;
 445    map->length = length;
 446    map->next = *mpp;
 447    *mpp = map;
 448out:
 449    map->formatter = formatter;
 450    return JS_TRUE;
 451}
 452
 453JS_PUBLIC_API(void)
 454JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
 455{
 456    size_t length;
 457    JSArgumentFormatMap **mpp, *map;
 458
 459    length = strlen(format);
 460    mpp = &cx->argumentFormatMap;
 461    while ((map = *mpp) != NULL) {
 462        if (map->length == length && !strcmp(map->format, format)) {
 463            *mpp = map->next;
 464            JS_free(cx, map);
 465            return;
 466        }
 467        mpp = &map->next;
 468    }
 469}
 470
 471JS_PUBLIC_API(JSBool)
 472JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
 473{
 474    JSBool ok;
 475    JSObject *obj;
 476    JSString *str;
 477    jsdouble d, *dp;
 478
 479    CHECK_REQUEST(cx);
 480    switch (type) {
 481      case JSTYPE_VOID:
 482        *vp = JSVAL_VOID;
 483        ok = JS_TRUE;
 484        break;
 485      case JSTYPE_OBJECT:
 486        ok = js_ValueToObject(cx, v, &obj);
 487        if (ok)
 488            *vp = OBJECT_TO_JSVAL(obj);
 489        break;
 490      case JSTYPE_FUNCTION:
 491        *vp = v;
 492        obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
 493        ok = (obj != NULL);
 494        break;
 495      case JSTYPE_STRING:
 496        str = js_ValueToString(cx, v);
 497        ok = (str != NULL);
 498        if (ok)
 499            *vp = STRING_TO_JSVAL(str);
 500        break;
 501      case JSTYPE_NUMBER:
 502        ok = JS_ValueToNumber(cx, v, &d);
 503        if (ok) {
 504            dp = js_NewWeaklyRootedDouble(cx, d);
 505            ok = (dp != NULL);
 506            if (ok)
 507                *vp = DOUBLE_TO_JSVAL(dp);
 508        }
 509        break;
 510      case JSTYPE_BOOLEAN:
 511        *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
 512        return JS_TRUE;
 513      default: {
 514        char numBuf[12];
 515        JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
 516        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
 517                             numBuf);
 518        ok = JS_FALSE;
 519        break;
 520      }
 521    }
 522    return ok;
 523}
 524
 525JS_PUBLIC_API(JSBool)
 526JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
 527{
 528    CHECK_REQUEST(cx);
 529    return js_ValueToObject(cx, v, objp);
 530}
 531
 532JS_PUBLIC_API(JSFunction *)
 533JS_ValueToFunction(JSContext *cx, jsval v)
 534{
 535    CHECK_REQUEST(cx);
 536    return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
 537}
 538
 539JS_PUBLIC_API(JSFunction *)
 540JS_ValueToConstructor(JSContext *cx, jsval v)
 541{
 542    CHECK_REQUEST(cx);
 543    return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
 544}
 545
 546JS_PUBLIC_API(JSString *)
 547JS_ValueToString(JSContext *cx, jsval v)
 548{
 549    CHECK_REQUEST(cx);
 550    return js_ValueToString(cx, v);
 551}
 552
 553JS_PUBLIC_API(JSString *)
 554JS_ValueToSource(JSContext *cx, jsval v)
 555{
 556    CHECK_REQUEST(cx);
 557    return js_ValueToSource(cx, v);
 558}
 559
 560JS_PUBLIC_API(JSBool)
 561JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
 562{
 563    JSTempValueRooter tvr;
 564
 565    CHECK_REQUEST(cx);
 566    JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
 567    *dp = js_ValueToNumber(cx, &tvr.u.value);
 568    JS_POP_TEMP_ROOT(cx, &tvr);
 569    return !JSVAL_IS_NULL(tvr.u.value);
 570}
 571
 572JS_PUBLIC_API(JSBool)
 573JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
 574{
 575    JSTempValueRooter tvr;
 576
 577    CHECK_REQUEST(cx);
 578    JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
 579    *ip = js_ValueToECMAInt32(cx, &tvr.u.value);
 580    JS_POP_TEMP_ROOT(cx, &tvr);
 581    return !JSVAL_IS_NULL(tvr.u.value);
 582}
 583
 584JS_PUBLIC_API(JSBool)
 585JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
 586{
 587    JSTempValueRooter tvr;
 588
 589    CHECK_REQUEST(cx);
 590    JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
 591    *ip = js_ValueToECMAUint32(cx, &tvr.u.value);
 592    JS_POP_TEMP_ROOT(cx, &tvr);
 593    return !JSVAL_IS_NULL(tvr.u.value);
 594}
 595
 596JS_PUBLIC_API(JSBool)
 597JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
 598{
 599    JSTempValueRooter tvr;
 600
 601    CHECK_REQUEST(cx);
 602    JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
 603    *ip = js_ValueToInt32(cx, &tvr.u.value);
 604    JS_POP_TEMP_ROOT(cx, &tvr);
 605    return !JSVAL_IS_NULL(tvr.u.value);
 606}
 607
 608JS_PUBLIC_API(JSBool)
 609JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
 610{
 611    JSTempValueRooter tvr;
 612
 613    CHECK_REQUEST(cx);
 614    JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
 615    *ip = js_ValueToUint16(cx, &tvr.u.value);
 616    JS_POP_TEMP_ROOT(cx, &tvr);
 617    return !JSVAL_IS_NULL(tvr.u.value);
 618}
 619
 620JS_PUBLIC_API(JSBool)
 621JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 622{
 623    CHECK_REQUEST(cx);
 624    *bp = js_ValueToBoolean(v);
 625    return JS_TRUE;
 626}
 627
 628JS_PUBLIC_API(JSType)
 629JS_TypeOfValue(JSContext *cx, jsval v)
 630{
 631    JSType type;
 632    JSObject *obj;
 633    JSObjectOps *ops;
 634    JSClass *clasp;
 635
 636    CHECK_REQUEST(cx);
 637    if (JSVAL_IS_OBJECT(v)) {
 638        type = JSTYPE_OBJECT;           /* XXXbe JSTYPE_NULL for JS2 */
 639        obj = JSVAL_TO_OBJECT(v);
 640        if (obj) {
 641            JSObject *wrapped;
 642
 643            wrapped = js_GetWrappedObject(cx, obj);
 644            if (wrapped)
 645                obj = wrapped;
 646
 647            ops = obj->map->ops;
 648#if JS_HAS_XML_SUPPORT
 649            if (ops == &js_XMLObjectOps.base) {
 650                type = JSTYPE_XML;
 651            } else
 652#endif
 653            {
 654                /*
 655                 * ECMA 262, 11.4.3 says that any native object that implements
 656                 * [[Call]] should be of type "function". Note that RegExp and
 657                 * Script are both of type "function" for compatibility with
 658                 * older SpiderMonkeys.
 659                 */
 660                clasp = OBJ_GET_CLASS(cx, obj);
 661                if ((ops == &js_ObjectOps)
 662                    ? (clasp->call
 663                       ? clasp == &js_ScriptClass
 664                       : clasp == &js_FunctionClass)
 665                    : ops->call != NULL) {
 666                    type = JSTYPE_FUNCTION;
 667                } else {
 668#ifdef NARCISSUS
 669                    JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 670
 671                    if (!OBJ_GET_PROPERTY(cx, obj,
 672                                          ATOM_TO_JSID(cx->runtime->atomState
 673                                                       .__call__Atom),
 674                                          &v)) {
 675                        JS_ClearPendingException(cx);
 676                    } else if (VALUE_IS_FUNCTION(cx, v)) {
 677                        type = JSTYPE_FUNCTION;
 678                    }
 679#endif
 680                }
 681            }
 682        }
 683    } else if (JSVAL_IS_NUMBER(v)) {
 684        type = JSTYPE_NUMBER;
 685    } else if (JSVAL_IS_STRING(v)) {
 686        type = JSTYPE_STRING;
 687    } else if (JSVAL_IS_BOOLEAN(v)) {
 688        type = JSTYPE_BOOLEAN;
 689    } else {
 690        type = JSTYPE_VOID;
 691    }
 692    return type;
 693}
 694
 695JS_PUBLIC_API(const char *)
 696JS_GetTypeName(JSContext *cx, JSType type)
 697{
 698    if ((uintN)type >= (uintN)JSTYPE_LIMIT)
 699        return NULL;
 700    return JS_TYPE_STR(type);
 701}
 702
 703/************************************************************************/
 704
 705/*
 706 * Has a new runtime ever been created?  This flag is used to detect unsafe
 707 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
 708 * ensure that "first checks" on runtime creation are run only once.
 709 */
 710#ifdef DEBUG
 711static JSBool js_NewRuntimeWasCalled = JS_FALSE;
 712#endif
 713
 714JS_PUBLIC_API(JSRuntime *)
 715JS_NewRuntime(uint32 maxbytes)
 716{
 717    JSRuntime *rt;
 718
 719#ifdef DEBUG
 720    if (!js_NewRuntimeWasCalled) {
 721        /*
 722         * This code asserts that the numbers associated with the error names
 723         * in jsmsg.def are monotonically increasing.  It uses values for the
 724         * error names enumerated in jscntxt.c.  It's not a compile-time check
 725         * but it's better than nothing.
 726         */
 727        int errorNumber = 0;
 728#define MSG_DEF(name, number, count, exception, format)                       \
 729    JS_ASSERT(name == errorNumber++);
 730#include "js.msg"
 731#undef MSG_DEF
 732
 733#define MSG_DEF(name, number, count, exception, format)                       \
 734    JS_BEGIN_MACRO                                                            \
 735        uintN numfmtspecs = 0;                                                \
 736        const char *fmt;                                                      \
 737        for (fmt = format; *fmt != '\0'; fmt++) {                             \
 738            if (*fmt == '{' && isdigit(fmt[1]))                               \
 739                ++numfmtspecs;                                                \
 740        }                                                                     \
 741        JS_ASSERT(count == numfmtspecs);                                      \
 742    JS_END_MACRO;
 743#include "js.msg"
 744#undef MSG_DEF
 745
 746        js_NewRuntimeWasCalled = JS_TRUE;
 747    }
 748#endif /* DEBUG */
 749
 750    rt = (JSRuntime *) malloc(sizeof(JSRuntime));
 751    if (!rt)
 752        return NULL;
 753
 754    /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
 755    memset(rt, 0, sizeof(JSRuntime));
 756    JS_INIT_CLIST(&rt->contextList);
 757    JS_INIT_CLIST(&rt->trapList);
 758    JS_INIT_CLIST(&rt->watchPointList);
 759
 760    if (!js_InitDtoa())
 761        goto bad;
 762    if (!js_InitGC(rt, maxbytes))
 763        goto bad;
 764    if (!js_InitAtomState(rt))
 765        goto bad;
 766    if (!js_InitDeflatedStringCache(rt))
 767        goto bad;
 768#ifdef JS_THREADSAFE
 769    if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
 770        goto bad;
 771    rt->gcLock = JS_NEW_LOCK();
 772    if (!rt->gcLock)
 773        goto bad;
 774    rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
 775    if (!rt->gcDone)
 776        goto bad;
 777    rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
 778    if (!rt->requestDone)
 779        goto bad;
 780    /* this is asymmetric with JS_ShutDown: */
 781    if (!js_SetupLocks(8, 16))
 782        goto bad;
 783    rt->rtLock = JS_NEW_LOCK();
 784    if (!rt->rtLock)
 785        goto bad;
 786    rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
 787    if (!rt->stateChange)
 788        goto bad;
 789    rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock);
 790    if (!rt->titleSharingDone)
 791        goto bad;
 792    rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
 793    rt->debuggerLock = JS_NEW_LOCK();
 794    if (!rt->debuggerLock)
 795        goto bad;
 796#endif
 797    if (!js_InitPropertyTree(rt))
 798        goto bad;
 799
 800#if !defined JS_THREADSAFE && defined JS_TRACER
 801    js_InitJIT(&rt->traceMonitor);
 802#endif
 803
 804    return rt;
 805
 806bad:
 807    JS_DestroyRuntime(rt);
 808    return NULL;
 809}
 810
 811JS_PUBLIC_API(void)
 812JS_DestroyRuntime(JSRuntime *rt)
 813{
 814#ifdef DEBUG
 815    /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
 816    if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
 817        JSContext *cx, *iter = NULL;
 818        uintN cxcount = 0;
 819        while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
 820            fprintf(stderr,
 821"JS API usage error: found live context at %p\n",
 822                    cx);
 823            cxcount++;
 824        }
 825        fprintf(stderr,
 826"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
 827                cxcount, (cxcount == 1) ? "" : "s");
 828    }
 829#endif
 830
 831#if !defined JS_THREADSAFE && defined JS_TRACER
 832    js_FinishJIT(&rt->traceMonitor);
 833#endif
 834
 835    js_FreeRuntimeScriptState(rt);
 836    js_FinishAtomState(rt);
 837
 838    /*
 839     * Free unit string storage only after all strings have been finalized, so
 840     * that js_FinalizeString can detect unit strings and avoid calling free
 841     * on their chars storage.
 842     */
 843    js_FinishUnitStrings(rt);
 844
 845    /*
 846     * Finish the deflated string cache after the last GC and after
 847     * calling js_FinishAtomState, which finalizes strings.
 848     */
 849    js_FinishDeflatedStringCache(rt);
 850    js_FinishGC(rt);
 851#ifdef JS_THREADSAFE
 852    if (rt->gcLock)
 853        JS_DESTROY_LOCK(rt->gcLock);
 854    if (rt->gcDone)
 855        JS_DESTROY_CONDVAR(rt->gcDone);
 856    if (rt->requestDone)
 857        JS_DESTROY_CONDVAR(rt->requestDone);
 858    if (rt->rtLock)
 859        JS_DESTROY_LOCK(rt->rtLock);
 860    if (rt->stateChange)
 861        JS_DESTROY_CONDVAR(rt->stateChange);
 862    if (rt->titleSharingDone)
 863        JS_DESTROY_CONDVAR(rt->titleSharingDone);
 864    if (rt->debuggerLock)
 865        JS_DESTROY_LOCK(rt->debuggerLock);
 866#else
 867    GSN_CACHE_CLEAR(&rt->gsnCache);
 868#endif
 869    js_FinishPropertyTree(rt);
 870    free(rt);
 871}
 872
 873JS_PUBLIC_API(void)
 874JS_ShutDown(void)
 875{
 876#ifdef JS_OPMETER
 877    extern void js_DumpOpMeters();
 878
 879    js_DumpOpMeters();
 880#endif
 881
 882    js_FinishDtoa();
 883#ifdef JS_THREADSAFE
 884    js_CleanupLocks();
 885#endif
 886    PRMJ_NowShutdown();
 887}
 888
 889JS_PUBLIC_API(void *)
 890JS_GetRuntimePrivate(JSRuntime *rt)
 891{
 892    return rt->data;
 893}
 894
 895JS_PUBLIC_API(void)
 896JS_SetRuntimePrivate(JSRuntime *rt, void *data)
 897{
 898    rt->data = data;
 899}
 900
 901JS_PUBLIC_API(void)
 902JS_BeginRequest(JSContext *cx)
 903{
 904#ifdef JS_THREADSAFE
 905    JSRuntime *rt;
 906
 907    JS_ASSERT(cx->thread->id == js_CurrentThreadId());
 908    if (!cx->requestDepth) {
 909        JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
 910
 911        /* Wait until the GC is finished. */
 912        rt = cx->runtime;
 913        JS_LOCK_GC(rt);
 914
 915        /* NB: we use cx->thread here, not js_GetCurrentThread(). */
 916        if (rt->gcThread != cx->thread) {
 917            while (rt->gcLevel > 0)
 918                JS_AWAIT_GC_DONE(rt);
 919        }
 920
 921        /* Indicate that a request is running. */
 922        rt->requestCount++;
 923        cx->requestDepth = 1;
 924        cx->outstandingRequests++;
 925        JS_UNLOCK_GC(rt);
 926        return;
 927    }
 928    cx->requestDepth++;
 929    cx->outstandingRequests++;
 930#endif
 931}
 932
 933JS_PUBLIC_API(void)
 934JS_EndRequest(JSContext *cx)
 935{
 936#ifdef JS_THREADSAFE
 937    JSRuntime *rt;
 938    JSTitle *title, **todop;
 939    JSBool shared;
 940
 941    CHECK_REQUEST(cx);
 942    JS_ASSERT(cx->requestDepth > 0);
 943    JS_ASSERT(cx->outstandingRequests > 0);
 944    if (cx->requestDepth == 1) {
 945        /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
 946        rt = cx->runtime;
 947        JS_LOCK_GC(rt);
 948        cx->requestDepth = 0;
 949        cx->outstandingRequests--;
 950
 951        /* See whether cx has any single-threaded titles to start sharing. */
 952        todop = &rt->titleSharingTodo;
 953        shared = JS_FALSE;
 954        while ((title = *todop) != NO_TITLE_SHARING_TODO) {
 955            if (title->ownercx != cx) {
 956                todop = &title->u.link;
 957                continue;
 958            }
 959            *todop = title->u.link;
 960            title->u.link = NULL;       /* null u.link for sanity ASAP */
 961
 962            /*
 963             * If js_DropObjectMap returns null, we held the last ref to scope.
 964             * The waiting thread(s) must have been killed, after which the GC
 965             * collected the object that held this scope.  Unlikely, because it
 966             * requires that the GC ran (e.g., from an operation callback)
 967             * during this request, but possible.
 968             */
 969            if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
 970                js_InitLock(&title->lock);
 971                title->u.count = 0;   /* NULL may not pun as 0 */
 972                js_FinishSharingTitle(cx, title); /* set ownercx = NULL */
 973                shared = JS_TRUE;
 974            }
 975        }
 976        if (shared)
 977            JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
 978
 979        js_RevokeGCLocalFreeLists(cx);
 980
 981        /* Give the GC a chance to run if this was the last request running. */
 982        JS_ASSERT(rt->requestCount > 0);
 983        rt->requestCount--;
 984        if (rt->requestCount == 0)
 985            JS_NOTIFY_REQUEST_DONE(rt);
 986
 987        JS_UNLOCK_GC(rt);
 988        return;
 989    }
 990
 991    cx->requestDepth--;
 992    cx->outstandingRequests--;
 993#endif
 994}
 995
 996/* Yield to pending GC operations, regardless of request depth */
 997JS_PUBLIC_API(void)
 998JS_YieldRequest(JSContext *cx)
 999{
1000#ifdef JS_THREADSAFE
1001    JS_ASSERT(cx->thread);
1002    CHECK_REQUEST(cx);
1003    JS_ResumeRequest(cx, JS_SuspendRequest(cx));
1004#endif
1005}
1006
1007JS_PUBLIC_API(jsrefcount)
1008JS_SuspendRequest(JSContext *cx)
1009{
1010#ifdef JS_THREADSAFE
1011    jsrefcount saveDepth = cx->requestDepth;
1012
1013    while (cx->requestDepth) {
1014        cx->outstandingRequests++;  /* compensate for JS_EndRequest */
1015        JS_EndRequest(cx);
1016    }
1017    return saveDepth;
1018#else
1019    return 0;
1020#endif
1021}
1022
1023JS_PUBLIC_API(void)
1024JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
1025{
1026#ifdef JS_THREADSAFE
1027    JS_ASSERT(!cx->requestDepth);
1028    while (--saveDepth >= 0) {
1029        JS_BeginRequest(cx);
1030        cx->outstandingRequests--;  /* compensate for JS_BeginRequest */
1031    }
1032#endif
1033}
1034
1035JS_PUBLIC_API(void)
1036JS_Lock(JSRuntime *rt)
1037{
1038    JS_LOCK_RUNTIME(rt);
1039}
1040
1041JS_PUBLIC_API(void)
1042JS_Unlock(JSRuntime *rt)
1043{
1044    JS_UNLOCK_RUNTIME(rt);
1045}
1046
1047JS_PUBLIC_API(JSContextCallback)
1048JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
1049{
1050    JSContextCallback old;
1051
1052    old = rt->cxCallback;
1053    rt->cxCallback = cxCallback;
1054    return old;
1055}
1056
1057JS_PUBLIC_API(JSContext *)
1058JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
1059{
1060    return js_NewContext(rt, stackChunkSize);
1061}
1062
1063JS_PUBLIC_API(void)
1064JS_DestroyContext(JSContext *cx)
1065{
1066    js_DestroyContext(cx, JSDCM_FORCE_GC);
1067}
1068
1069JS_PUBLIC_API(void)
1070JS_DestroyContextNoGC(JSContext *cx)
1071{
1072    js_DestroyContext(cx, JSDCM_NO_GC);
1073}
1074
1075JS_PUBLIC_API(void)
1076JS_DestroyContextMaybeGC(JSContext *cx)
1077{
1078    js_DestroyContext(cx, JSDCM_MAYBE_GC);
1079}
1080
1081JS_PUBLIC_API(void *)
1082JS_GetContextPrivate(JSContext *cx)
1083{
1084    return cx->data;
1085}
1086
1087JS_PUBLIC_API(void)
1088JS_SetContextPrivate(JSContext *cx, void *data)
1089{
1090    cx->data = data;
1091}
1092
1093JS_PUBLIC_API(JSRuntime *)
1094JS_GetRuntime(JSContext *cx)
1095{
1096    return cx->runtime;
1097}
1098
1099JS_PUBLIC_API(JSContext *)
1100JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1101{
1102    return js_ContextIterator(rt, JS_TRUE, iterp);
1103}
1104
1105JS_PUBLIC_API(JSVersion)
1106JS_GetVersion(JSContext *cx)
1107{
1108    return JSVERSION_NUMBER(cx);
1109}
1110
1111JS_PUBLIC_API(JSVersion)
1112JS_SetVersion(JSContext *cx, JSVersion version)
1113{
1114    JSVersion oldVersion;
1115
1116    JS_ASSERT(version != JSVERSION_UNKNOWN);
1117    JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1118
1119    oldVersion = JSVERSION_NUMBER(cx);
1120    if (version == oldVersion)
1121        return oldVersion;
1122
1123    /* We no longer support 1.4 or below. */
1124    if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1125        return oldVersion;
1126
1127    cx->version = (cx->version & ~JSVERSION_MASK) | version;
1128    js_OnVersionChange(cx);
1129    return oldVersion;
1130}
1131
1132static struct v2smap {
1133    JSVersion   version;
1134    const char  *string;
1135} v2smap[] = {
1136    {JSVERSION_1_0,     "1.0"},
1137    {JSVERSION_1_1,     "1.1"},
1138    {JSVERSION_1_2,     "1.2"},
1139    {JSVERSION_1_3,     "1.3"},
1140    {JSVERSION_1_4,     "1.4"},
1141    {JSVERSION_ECMA_3,  "ECMAv3"},
1142    {JSVERSION_1_5,     "1.5"},
1143    {JSVERSION_1_6,     "1.6"},
1144    {JSVERSION_1_7,     "1.7"},
1145    {JSVERSION_1_8,     "1.8"},
1146    {JSVERSION_DEFAULT, js_default_str},
1147    {JSVERSION_UNKNOWN, NULL},          /* must be last, NULL is sentinel */
1148};
1149
1150JS_PUBLIC_API(const char *)
1151JS_VersionToString(JSVersion version)
1152{
1153    int i;
1154
1155    for (i = 0; v2smap[i].string; i++)
1156        if (v2smap[i].version == version)
1157            return v2smap[i].string;
1158    return "unknown";
1159}
1160
1161JS_PUBLIC_API(JSVersion)
1162JS_StringToVersion(const char *string)
1163{
1164    int i;
1165
1166    for (i = 0; v2smap[i].string; i++)
1167        if (strcmp(v2smap[i].string, string) == 0)
1168            return v2smap[i].version;
1169    return JSVERSION_UNKNOWN;
1170}
1171
1172JS_PUBLIC_API(uint32)
1173JS_GetOptions(JSContext *cx)
1174{
1175    return cx->options;
1176}
1177
1178#define SYNC_OPTIONS_TO_VERSION(cx)                                           \
1179    JS_BEGIN_MACRO                                                            \
1180        if ((cx)->options & JSOPTION_XML)                                     \
1181            (cx)->version |= JSVERSION_HAS_XML;                               \
1182        else                                                                  \
1183            (cx)->version &= ~JSVERSION_HAS_XML;                              \
1184    JS_END_MACRO
1185
1186JS_PUBLIC_API(uint32)
1187JS_SetOptions(JSContext *cx, uint32 options)
1188{
1189    uint32 oldopts = cx->options;
1190    cx->options = options;
1191    SYNC_OPTIONS_TO_VERSION(cx);
1192    return oldopts;
1193}
1194
1195JS_PUBLIC_API(uint32)
1196JS_ToggleOptions(JSContext *cx, uint32 options)
1197{
1198    uint32 oldopts = cx->options;
1199    cx->options ^= options;
1200    SYNC_OPTIONS_TO_VERSION(cx);
1201    return oldopts;
1202}
1203
1204JS_PUBLIC_API(const char *)
1205JS_GetImplementationVersion(void)
1206{
1207    return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1208}
1209
1210
1211JS_PUBLIC_API(JSObject *)
1212JS_GetGlobalObject(JSContext *cx)
1213{
1214    return cx->globalObject;
1215}
1216
1217JS_PUBLIC_API(void)
1218JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1219{
1220    cx->globalObject = obj;
1221
1222#if JS_HAS_XML_SUPPORT
1223    cx->xmlSettingFlags = 0;
1224#endif
1225}
1226
1227JS_BEGIN_EXTERN_C
1228
1229JSObject *
1230js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1231{
1232    JSDHashTable *table;
1233    JSBool resolving;
1234    JSRuntime *rt;
1235    JSResolvingKey key;
1236    JSResolvingEntry *entry;
1237    JSObject *fun_proto, *obj_proto;
1238
1239    /* If cx has no global object, use obj so prototypes can be found. */
1240    if (!cx->globalObject)
1241        JS_SetGlobalObject(cx, obj);
1242
1243    /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1244    table = cx->resolvingTable;
1245    resolving = (table && table->entryCount);
1246    rt = cx->runtime;
1247    key.obj = obj;
1248    if (resolving) {
1249        key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1250        entry = (JSResolvingEntry *)
1251                JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1252        if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1253            /* Already resolving Function, record Object too. */
1254            JS_ASSERT(entry->key.obj == obj);
1255            key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1256            entry = (JSResolvingEntry *)
1257                    JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1258        }
1259        if (!entry) {
1260            JS_ReportOutOfMemory(cx);
1261            return NULL;
1262        }
1263        JS_ASSERT(!entry->key.obj && entry->flags == 0);
1264        entry->key = key;
1265        entry->flags = JSRESFLAG_LOOKUP;
1266    } else {
1267        key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1268        if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
1269            return NULL;
1270
1271        key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1272        if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
1273            key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1274            JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1275            return NULL;
1276        }
1277
1278        table = cx->resolvingTable;
1279    }
1280
1281    /* Initialize the function class first so constructors can be made. */
1282    if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function),
1283                              &fun_proto)) {
1284        fun_proto = NULL;
1285        goto out;
1286    }
1287    if (!fun_proto) {
1288        fun_proto = js_InitFunctionClass(cx, obj);
1289        if (!fun_proto)
1290            goto out;
1291    } else {
1292        JSObject *ctor;
1293
1294        ctor = JS_GetConstructor(cx, fun_proto);
1295        if (!ctor) {
1296            fun_proto = NULL;
1297            goto out;
1298        }
1299        OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1300                            OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL);
1301    }
1302
1303    /* Initialize the object class next so Object.prototype works. */
1304    if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1305                              &obj_proto)) {
1306        fun_proto = NULL;
1307        goto out;
1308    }
1309    if (!obj_proto)
1310        obj_proto = js_InitObjectClass(cx, obj);
1311    if (!obj_proto) {
1312        fun_proto = NULL;
1313        goto out;
1314    }
1315
1316    /* Function.prototype and the global object delegate to Object.prototype. */
1317    OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1318    if (!OBJ_GET_PROTO(cx, obj))
1319        OBJ_SET_PROTO(cx, obj, obj_proto);
1320
1321out:
1322    /* If resolving, remove the other entry (Object or Function) from table. */
1323    JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1324    if (!resolving) {
1325        /* If not resolving, remove the first entry added above, for Object. */
1326        JS_ASSERT(key.id ==                                                   \
1327                  ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
1328        key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1329        JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1330    }
1331    return fun_proto;
1332}
1333
1334JS_END_EXTERN_C
1335
1336JS_PUBLIC_API(JSBool)
1337JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1338{
1339    JSAtom *atom;
1340
1341    CHECK_REQUEST(cx);
1342
1343    /* Define a top-level property 'undefined' with the undefined value. */
1344    atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1345    if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1346                             NULL, NULL, JSPROP_PERMANENT, NULL)) {
1347        return JS_FALSE;
1348    }
1349
1350    /* Function and Object require cooperative bootstrapping magic. */
1351    if (!js_InitFunctionAndObjectClasses(cx, obj))
1352        return JS_FALSE;
1353
1354    /* Initialize the rest of the standard objects and functions. */
1355    return js_InitArrayClass(cx, obj) &&
1356           js_InitBlockClass(cx, obj) &&
1357           js_InitBooleanClass(cx, obj) &&
1358           js_InitCallClass(cx, obj) &&
1359           js_InitExceptionClasses(cx, obj) &&
1360           js_InitMathClass(cx, obj) &&
1361           js_InitNumberClass(cx, obj) &&
1362           js_InitJSONClass(cx, obj) &&
1363           js_InitRegExpClass(cx, obj) &&
1364           js_InitStringClass(cx, obj) &&
1365           js_InitEval(cx, obj) &&
1366#if JS_HAS_SCRIPT_OBJECT
1367           js_InitScriptClass(cx, obj) &&
1368#endif
1369#if JS_HAS_XML_SUPPORT
1370           js_InitXMLClasses(cx, obj) &&
1371#endif
1372#if JS_HAS_FILE_OBJECT
1373           js_InitFileClass(cx, obj) &&
1374#endif
1375#if JS_HAS_GENERATORS
1376           js_InitIteratorClasses(cx, obj) &&
1377#endif
1378           js_InitDateClass(cx, obj);
1379}
1380
1381#define CLASP(name)                 (&js_##name##Class)
1382#define EXT_CLASP(name)             (&js_##name##Class.base)
1383#define EAGER_ATOM(name)            ATOM_OFFSET(name), NULL
1384#define EAGER_CLASS_ATOM(name)      CLASS_ATOM_OFFSET(name), NULL
1385#define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
1386#define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
1387#define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
1388
1389typedef struct JSStdName {
1390    JSObjectOp  init;
1391    size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
1392    const char  *name;          /* null if atom is pre-pinned, else name */
1393    JSClass     *clasp;
1394} JSStdName;
1395
1396static JSAtom *
1397StdNameToAtom(JSContext *cx, JSStdName *stdn)
1398{
1399    size_t offset;
1400    JSAtom *atom;
1401    const char *name;
1402
1403    offset = stdn->atomOffset;
1404    atom = OFFSET_TO_ATOM(cx->runtime, offset);
1405    if (!atom) {
1406        name = stdn->name;
1407        if (name) {
1408            atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1409            OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1410        }
1411    }
1412    return atom;
1413}
1414
1415/*
1416 * Table of class initializers and their atom offsets in rt->atomState.
1417 * If you add a "standard" class, remember to update this table.
1418 */
1419static JSStdName standard_class_atoms[] = {
1420    {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Function)},
1421    {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Object)},
1422    {js_InitArrayClass,                 EAGER_ATOM_AND_CLASP(Array)},
1423    {js_InitBlockClass,                 EAGER_ATOM_AND_CLASP(Block)},
1424    {js_InitBooleanClass,               EAGER_ATOM_AND_CLASP(Boolean)},
1425    {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
1426    {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
1427    {js_InitNumberClass,                EAGER_ATOM_AND_CLASP(Number)},
1428    {js_InitStringClass,                EAGER_ATOM_AND_CLASP(String)},
1429    {js_InitCallClass,                  EAGER_ATOM_AND_CLASP(Call)},
1430    {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
1431    {js_InitRegExpClass,                EAGER_ATOM_AND_CLASP(RegExp)},
1432#if JS_HAS_SCRIPT_OBJECT
1433    {js_InitScriptClass,                EAGER_ATOM_AND_CLASP(Script)},
1434#endif
1435#if JS_HAS_XML_SUPPORT
1436    {js_InitXMLClass,                   EAGER_ATOM_AND_CLASP(XML)},
1437    {js_InitNamespaceClass,             EAGER_ATOM_AND_EXT_CLASP(Namespace)},
1438    {js_InitQNameClass,                 EAGER_ATOM_AND_EXT_CLASP(QName)},
1439#endif
1440#if JS_HAS_FILE_OBJECT
1441    {js_InitFileClass,                  EAGER_ATOM_AND_CLASP(File)},
1442#endif
1443#if JS_HAS_GENERATORS
1444    {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
1445#endif
1446    {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
1447    {NULL,                              0, NULL, NULL}
1448};
1449
1450/*
1451 * Table of top-level function and constant names and their init functions.
1452 * If you add a "standard" global function or property, remember to update
1453 * this table.
1454 */
1455static JSStdName standard_class_names[] = {
1456    /* ECMA requires that eval be a direct property of the global object. */
1457    {js_InitEval,               EAGER_ATOM(eval), NULL},
1458
1459    /* Global properties and functions defined by the Number class. */
1460    {js_InitNumberClass,        LAZY_ATOM(NaN), NULL},
1461    {js_InitNumberClass,        LAZY_ATOM(Infinity), NULL},
1462    {js_InitNumberClass,        LAZY_ATOM(isNaN), NULL},
1463    {js_InitNumberClass,        LAZY_ATOM(isFinite), NULL},
1464    {js_InitNumberClass,        LAZY_ATOM(parseFloat), NULL},
1465    {js_InitNumberClass,        LAZY_ATOM(parseInt), NULL},
1466
1467    /* String global functions. */
1468    {js_InitStringClass,        LAZY_ATOM(escape), NULL},
1469    {js_InitStringClass,        LAZY_ATOM(unescape), NULL},
1470    {js_InitStringClass,        LAZY_ATOM(decodeURI), NULL},
1471    {js_InitStringClass,        LAZY_ATOM(encodeURI), NULL},
1472    {js_InitStringClass,        LAZY_ATOM(decodeURIComponent), NULL},
1473    {js_InitStringClass,        LAZY_ATOM(encodeURIComponent), NULL},
1474#if JS_HAS_UNEVAL
1475    {js_InitStringClass,        LAZY_ATOM(uneval), NULL},
1476#endif
1477
1478    /* Exception constructors. */
1479    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(Error), CLASP(Error)},
1480    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1481    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1482    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1483    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1484    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1485    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1486    {js_InitExceptionClasses,   EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1487
1488#if JS_HAS_XML_SUPPORT
1489    {js_InitAnyNameClass,       EAGER_ATOM_AND_CLASP(AnyName)},
1490    {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1491    {js_InitXMLClass,           LAZY_ATOM(XMLList), &js_XMLClass},
1492    {js_InitXMLClass,           LAZY_ATOM(isXMLName), NULL},
1493#endif
1494
1495#if JS_HAS_GENERATORS
1496    {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
1497    {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
1498#endif
1499
1500    {NULL,                      0, NULL, NULL}
1501};
1502
1503static JSStdName object_prototype_names[] = {
1504    /* Object.prototype properties (global delegates to Object.prototype). */
1505    {js_InitObjectClass,        EAGER_ATOM(proto), NULL},
1506    {js_InitObjectClass,        EAGER_ATOM(parent), NULL},
1507    {js_InitObjectClass,        EAGER_ATOM(count), NULL},
1508#if JS_HAS_TOSOURCE
1509    {js_InitObjectClass,        EAGER_ATOM(toSource), NULL},
1510#endif
1511    {js_InitObjectClass,        EAGER_ATOM(toString), NULL},
1512    {js_InitObjectClass,        EAGER_ATOM(toLocaleString), NULL},
1513    {js_InitObjectClass,        EAGER_ATOM(valueOf), NULL},
1514#if JS_HAS_OBJ_WATCHPOINT
1515    {js_InitObjectClass,        LAZY_ATOM(watch), NULL},
1516    {js_InitObjectClass,        LAZY_ATOM(unwatch), NULL},
1517#endif
1518    {js_InitObjectClass,        LAZY_ATOM(hasOwnProperty), NULL},
1519    {js_InitObjectClass,        LAZY_ATOM(isPrototypeOf), NULL},
1520    {js_InitObjectClass,        LAZY_ATOM(propertyIsEnumerable), NULL},
1521#if JS_HAS_GETTER_SETTER
1522    {js_InitObjectClass,        LAZY_ATOM(defineGetter), NULL},
1523    {js_InitObjectClass,        LAZY_ATOM(defineSetter), NULL},
1524    {js_InitObjectClass,        LAZY_ATOM(lookupGetter), NULL},
1525    {js_InitObjectClass,        LAZY_ATOM(lookupSetter), NULL},
1526#endif
1527
1528    {NULL,                      0, NULL, NULL}
1529};
1530
1531JS_PUBLIC_API(JSBool)
1532JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1533                        JSBool *resolved)
1534{
1535    JSString *idstr;
1536    JSRuntime *rt;
1537    JSAtom *atom;
1538    JSStdName *stdnm;
1539    uintN i;
1540
1541    CHECK_REQUEST(cx);
1542    *resolved = JS_FALSE;
1543
1544    rt = cx->runtime;
1545    JS_ASSERT(rt->state != JSRTS_DOWN);
1546    if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
1547        return JS_TRUE;
1548
1549    idstr = JSVAL_TO_STRING(id);
1550
1551    /* Check whether we're resolving 'undefined', and define it if so. */
1552    atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1553    if (idstr == ATOM_TO_STRING(atom)) {
1554        *resolved = JS_TRUE;
1555        return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1556                                   NULL, NULL, JSPROP_PERMANENT, NULL);
1557    }
1558
1559    /* Try for class constructors/prototypes named by well-known atoms. */
1560    stdnm = NULL;
1561    for (i = 0; standard_class_atoms[i].init; i++) {
1562        atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1563        if (idstr == ATOM_TO_STRING(atom)) {
1564            stdnm = &standard_class_atoms[i];
1565            break;
1566        }
1567    }
1568
1569    if (!stdnm) {
1570        /* Try less frequently used top-level functions and constants. */
1571        for (i = 0; standard_class_names[i].init; i++) {
1572            atom = StdNameToAtom(cx, &standard_class_names[i]);
1573            if (!atom)
1574                return JS_FALSE;
1575            if (idstr == ATOM_TO_STRING(atom)) {
1576                stdnm = &standard_class_names[i];
1577                break;
1578            }
1579        }
1580
1581        if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
1582            /*
1583             * Try even less frequently used names delegated from the global
1584             * object to Object.prototype, but only if the Object class hasn't
1585             * yet been initialized.
1586             */
1587            for (i = 0; object_prototype_names[i].init; i++) {
1588                atom = StdNameToAtom(cx, &object_prototype_names[i]);
1589                if (!atom)
1590                    return JS_FALSE;
1591                if (idstr == ATOM_TO_STRING(atom)) {
1592                    stdnm = &standard_class_names[i];
1593                    break;
1594                }
1595            }
1596        }
1597    }
1598
1599    if (stdnm) {
1600        /*
1601         * If this standard class is anonymous and obj advertises itself as a
1602         * global object (in order to reserve slots for standard class object
1603         * pointers), then we don't want to resolve by name.
1604         *
1605         * If inversely, either id does not name a class, or id does not name
1606         * an anonymous class, or the global does not reserve slots for class
1607         * objects, then we must call the init hook here.
1608         */
1609        if (stdnm->clasp &&
1610            (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
1611            (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
1612            return JS_TRUE;
1613        }
1614
1615        if (!stdnm->init(cx, obj))
1616            return JS_FALSE;
1617        *resolved = JS_TRUE;
1618    }
1619    return JS_TRUE;
1620}
1621
1622static JSBool
1623AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1624{
1625    JSScopeProperty *sprop;
1626    JSScope *scope;
1627
1628    JS_ASSERT(OBJ_IS_NATIVE(obj));
1629    JS_LOCK_OBJ(cx, obj);
1630    scope = OBJ_SCOPE(obj);
1631    sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
1632    JS_UNLOCK_SCOPE(cx, scope);
1633    return sprop != NULL;
1634}
1635
1636JS_PUBLIC_API(JSBool)
1637JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1638{
1639    JSRuntime *rt;
1640    JSAtom *atom;
1641    uintN i;
1642
1643    CHECK_REQUEST(cx);
1644    rt = cx->runtime;
1645
1646    /* Check whether we need to bind 'undefined' and define it if so. */
1647    atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1648    if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1649        !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1650                             NULL, NULL, JSPROP_PERMANENT, NULL)) {
1651        return JS_FALSE;
1652    }
1653
1654    /* Initialize any classes that have not been resolved yet. */
1655    for (i = 0; standard_class_atoms[i].init; i++) {
1656        atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1657        if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1658            !standard_class_atoms[i].init(cx, obj)) {
1659            return JS_FALSE;
1660        }
1661    }
1662
1663    return JS_TRUE;
1664}
1665
1666static JSIdArray *
1667NewIdArray(JSContext *cx, jsint length)
1668{
1669    JSIdArray *ida;
1670
1671    ida = (JSIdArray *)
1672          JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
1673    if (ida)
1674        ida->length = length;
1675    return ida;
1676}
1677
1678/*
1679 * Unlike realloc(3), this function frees ida on failure.
1680 */
1681static JSIdArray *
1682SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1683{
1684    JSIdArray *rida;
1685
1686    rida = (JSIdArray *)
1687           JS_realloc(cx, ida,
1688                      offsetof(JSIdArray, vector) + length * sizeof(jsval));
1689    if (!rida)
1690        JS_DestroyIdArray(cx, ida);
1691    else
1692        rida->length = length;
1693    return rida;
1694}
1695
1696static JSIdArray *
1697AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1698{
1699    jsint i, length;
1700
1701    i = *ip;
1702    length = ida->length;
1703    if (i >= length) {
1704        ida = SetIdArrayLength(cx, ida, JS

Large files files are truncated, but you can click here to view the full file