Back to index

lightning-sunbird  0.9+nobinonly
jsfun.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=78:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042  * JS function support.
00043  */
00044 #include "jsstddef.h"
00045 #include <string.h>
00046 #include "jstypes.h"
00047 #include "jsbit.h"
00048 #include "jsutil.h" /* Added by JSIFY */
00049 #include "jsapi.h"
00050 #include "jsarray.h"
00051 #include "jsatom.h"
00052 #include "jscntxt.h"
00053 #include "jsconfig.h"
00054 #include "jsdbgapi.h"
00055 #include "jsfun.h"
00056 #include "jsgc.h"
00057 #include "jsinterp.h"
00058 #include "jslock.h"
00059 #include "jsnum.h"
00060 #include "jsobj.h"
00061 #include "jsopcode.h"
00062 #include "jsparse.h"
00063 #include "jsscan.h"
00064 #include "jsscope.h"
00065 #include "jsscript.h"
00066 #include "jsstr.h"
00067 #include "jsexn.h"
00068 
00069 #if JS_HAS_GENERATORS
00070 # include "jsiter.h"
00071 #endif
00072 
00073 /* Generic function/call/arguments tinyids -- also reflected bit numbers. */
00074 enum {
00075     CALL_ARGUMENTS  = -1,       /* predefined arguments local variable */
00076     CALL_CALLEE     = -2,       /* reference to active function's object */
00077     ARGS_LENGTH     = -3,       /* number of actual args, arity if inactive */
00078     ARGS_CALLEE     = -4,       /* reference from arguments to active funobj */
00079     FUN_ARITY       = -5,       /* number of formal parameters; desired argc */
00080     FUN_NAME        = -6,       /* function name, "" if anonymous */
00081     FUN_CALLER      = -7        /* Function.prototype.caller, backward compat */
00082 };
00083 
00084 #if JSFRAME_OVERRIDE_BITS < 8
00085 # error "not enough override bits in JSStackFrame.flags!"
00086 #endif
00087 
00088 #define TEST_OVERRIDE_BIT(fp, tinyid) \
00089     ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
00090 
00091 #define SET_OVERRIDE_BIT(fp, tinyid) \
00092     ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
00093 
00094 JSBool
00095 js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
00096 {
00097     JSObject *argsobj;
00098 
00099     if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
00100         JS_ASSERT(fp->callobj);
00101         return OBJ_GET_PROPERTY(cx, fp->callobj,
00102                                 ATOM_TO_JSID(cx->runtime->atomState
00103                                              .argumentsAtom),
00104                                 vp);
00105     }
00106     argsobj = js_GetArgsObject(cx, fp);
00107     if (!argsobj)
00108         return JS_FALSE;
00109     *vp = OBJECT_TO_JSVAL(argsobj);
00110     return JS_TRUE;
00111 }
00112 
00113 static JSBool
00114 MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
00115 {
00116     JSObject *argsobj;
00117     jsval bmapval, bmapint;
00118     size_t nbits, nbytes;
00119     jsbitmap *bitmap;
00120 
00121     argsobj = fp->argsobj;
00122     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
00123     nbits = fp->argc;
00124     JS_ASSERT(slot < nbits);
00125     if (JSVAL_IS_VOID(bmapval)) {
00126         if (nbits <= JSVAL_INT_BITS) {
00127             bmapint = 0;
00128             bitmap = (jsbitmap *) &bmapint;
00129         } else {
00130             nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap);
00131             bitmap = (jsbitmap *) JS_malloc(cx, nbytes);
00132             if (!bitmap)
00133                 return JS_FALSE;
00134             memset(bitmap, 0, nbytes);
00135             bmapval = PRIVATE_TO_JSVAL(bitmap);
00136             JS_SetReservedSlot(cx, argsobj, 0, bmapval);
00137         }
00138     } else {
00139         if (nbits <= JSVAL_INT_BITS) {
00140             bmapint = JSVAL_TO_INT(bmapval);
00141             bitmap = (jsbitmap *) &bmapint;
00142         } else {
00143             bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
00144         }
00145     }
00146     JS_SET_BIT(bitmap, slot);
00147     if (bitmap == (jsbitmap *) &bmapint) {
00148         bmapval = INT_TO_JSVAL(bmapint);
00149         JS_SetReservedSlot(cx, argsobj, 0, bmapval);
00150     }
00151     return JS_TRUE;
00152 }
00153 
00154 /* NB: Infallible predicate, false does not mean error/exception. */
00155 static JSBool
00156 ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
00157 {
00158     JSObject *argsobj;
00159     jsval bmapval, bmapint;
00160     jsbitmap *bitmap;
00161 
00162     argsobj = fp->argsobj;
00163     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
00164     if (JSVAL_IS_VOID(bmapval))
00165         return JS_FALSE;
00166     if (fp->argc <= JSVAL_INT_BITS) {
00167         bmapint = JSVAL_TO_INT(bmapval);
00168         bitmap = (jsbitmap *) &bmapint;
00169     } else {
00170         bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
00171     }
00172     return JS_TEST_BIT(bitmap, slot) != 0;
00173 }
00174 
00175 JSBool
00176 js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id,
00177                    JSObject **objp, jsval *vp)
00178 {
00179     jsval val;
00180     JSObject *obj;
00181     uintN slot;
00182 
00183     if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
00184         JS_ASSERT(fp->callobj);
00185         if (!OBJ_GET_PROPERTY(cx, fp->callobj,
00186                               ATOM_TO_JSID(cx->runtime->atomState
00187                                            .argumentsAtom),
00188                               &val)) {
00189             return JS_FALSE;
00190         }
00191         if (JSVAL_IS_PRIMITIVE(val)) {
00192             obj = js_ValueToNonNullObject(cx, val);
00193             if (!obj)
00194                 return JS_FALSE;
00195         } else {
00196             obj = JSVAL_TO_OBJECT(val);
00197         }
00198         *objp = obj;
00199         return OBJ_GET_PROPERTY(cx, obj, id, vp);
00200     }
00201 
00202     *objp = NULL;
00203     *vp = JSVAL_VOID;
00204     if (JSID_IS_INT(id)) {
00205         slot = (uintN) JSID_TO_INT(id);
00206         if (slot < fp->argc) {
00207             if (fp->argsobj && ArgWasDeleted(cx, fp, slot))
00208                 return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
00209             *vp = fp->argv[slot];
00210         } else {
00211             /*
00212              * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
00213              * storage between the formal parameter and arguments[k] for all
00214              * k >= fp->argc && k < fp->fun->nargs.  For example, in
00215              *
00216              *   function f(x) { x = 42; return arguments[0]; }
00217              *   f();
00218              *
00219              * the call to f should return undefined, not 42.  If fp->argsobj
00220              * is null at this point, as it would be in the example, return
00221              * undefined in *vp.
00222              */
00223             if (fp->argsobj)
00224                 return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
00225         }
00226     } else {
00227         if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
00228             if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH))
00229                 return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
00230             *vp = INT_TO_JSVAL((jsint) fp->argc);
00231         }
00232     }
00233     return JS_TRUE;
00234 }
00235 
00236 JSObject *
00237 js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
00238 {
00239     JSObject *argsobj, *global, *parent;
00240 
00241     /*
00242      * We must be in a function activation; the function must be lightweight
00243      * or else fp must have a variable object.
00244      */
00245     JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj));
00246 
00247     /* Skip eval and debugger frames. */
00248     while (fp->flags & JSFRAME_SPECIAL)
00249         fp = fp->down;
00250 
00251     /* Create an arguments object for fp only if it lacks one. */
00252     argsobj = fp->argsobj;
00253     if (argsobj)
00254         return argsobj;
00255 
00256     /* Link the new object to fp so it can get actual argument values. */
00257     argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
00258     if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
00259         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
00260         return NULL;
00261     }
00262 
00263     /*
00264      * Give arguments an intrinsic scope chain link to fp's global object.
00265      * Since the arguments object lacks a prototype because js_ArgumentsClass
00266      * is not initialized, js_NewObject won't assign a default parent to it.
00267      *
00268      * Therefore if arguments is used as the head of an eval scope chain (via
00269      * a direct or indirect call to eval(program, arguments)), any reference
00270      * to a standard class object in the program will fail to resolve due to
00271      * js_GetClassPrototype not being able to find a global object containing
00272      * the standard prototype by starting from arguments and following parent.
00273      */
00274     global = fp->scopeChain;
00275     while ((parent = OBJ_GET_PARENT(cx, global)) != NULL)
00276         global = parent;
00277     argsobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(global);
00278     fp->argsobj = argsobj;
00279     return argsobj;
00280 }
00281 
00282 static JSBool
00283 args_enumerate(JSContext *cx, JSObject *obj);
00284 
00285 JSBool
00286 js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
00287 {
00288     JSObject *argsobj;
00289     jsval bmapval, rval;
00290     JSBool ok;
00291     JSRuntime *rt;
00292 
00293     /*
00294      * Reuse args_enumerate here to reflect fp's actual arguments as indexed
00295      * elements of argsobj.  Do this first, before clearing and freeing the
00296      * deleted argument slot bitmap, because args_enumerate depends on that.
00297      */
00298     argsobj = fp->argsobj;
00299     ok = args_enumerate(cx, argsobj);
00300 
00301     /*
00302      * Now clear the deleted argument number bitmap slot and free the bitmap,
00303      * if one was actually created due to 'delete arguments[0]' or similar.
00304      */
00305     (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
00306     if (!JSVAL_IS_VOID(bmapval)) {
00307         JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
00308         if (fp->argc > JSVAL_INT_BITS)
00309             JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
00310     }
00311 
00312     /*
00313      * Now get the prototype properties so we snapshot fp->fun and fp->argc
00314      * before fp goes away.
00315      */
00316     rt = cx->runtime;
00317     ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
00318                          &rval);
00319     ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
00320                          &rval);
00321     ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
00322                          &rval);
00323     ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
00324                          &rval);
00325 
00326     /*
00327      * Clear the private pointer to fp, which is about to go away (js_Invoke).
00328      * Do this last because the args_enumerate and js_GetProperty calls above
00329      * need to follow the private slot to find fp.
00330      */
00331     ok &= JS_SetPrivate(cx, argsobj, NULL);
00332     fp->argsobj = NULL;
00333     return ok;
00334 }
00335 
00336 static JSBool
00337 args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00338 {
00339     jsint slot;
00340     JSStackFrame *fp;
00341 
00342     if (!JSVAL_IS_INT(id))
00343         return JS_TRUE;
00344     fp = (JSStackFrame *)
00345          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
00346     if (!fp)
00347         return JS_TRUE;
00348     JS_ASSERT(fp->argsobj);
00349 
00350     slot = JSVAL_TO_INT(id);
00351     switch (slot) {
00352       case ARGS_CALLEE:
00353       case ARGS_LENGTH:
00354         SET_OVERRIDE_BIT(fp, slot);
00355         break;
00356 
00357       default:
00358         if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot))
00359             return JS_FALSE;
00360         break;
00361     }
00362     return JS_TRUE;
00363 }
00364 
00365 static JSBool
00366 args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00367 {
00368     jsint slot;
00369     JSStackFrame *fp;
00370 
00371     if (!JSVAL_IS_INT(id))
00372         return JS_TRUE;
00373     fp = (JSStackFrame *)
00374          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
00375     if (!fp)
00376         return JS_TRUE;
00377     JS_ASSERT(fp->argsobj);
00378 
00379     slot = JSVAL_TO_INT(id);
00380     switch (slot) {
00381       case ARGS_CALLEE:
00382         if (!TEST_OVERRIDE_BIT(fp, slot))
00383             *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
00384         break;
00385 
00386       case ARGS_LENGTH:
00387         if (!TEST_OVERRIDE_BIT(fp, slot))
00388             *vp = INT_TO_JSVAL((jsint)fp->argc);
00389         break;
00390 
00391       default:
00392         if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot))
00393             *vp = fp->argv[slot];
00394         break;
00395     }
00396     return JS_TRUE;
00397 }
00398 
00399 static JSBool
00400 args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00401 {
00402     JSStackFrame *fp;
00403     jsint slot;
00404 
00405     if (!JSVAL_IS_INT(id))
00406         return JS_TRUE;
00407     fp = (JSStackFrame *)
00408          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
00409     if (!fp)
00410         return JS_TRUE;
00411     JS_ASSERT(fp->argsobj);
00412 
00413     slot = JSVAL_TO_INT(id);
00414     switch (slot) {
00415       case ARGS_CALLEE:
00416       case ARGS_LENGTH:
00417         SET_OVERRIDE_BIT(fp, slot);
00418         break;
00419 
00420       default:
00421         if (FUN_INTERPRETED(fp->fun) &&
00422             (uintN)slot < fp->argc &&
00423             !ArgWasDeleted(cx, fp, slot)) {
00424             fp->argv[slot] = *vp;
00425         }
00426         break;
00427     }
00428     return JS_TRUE;
00429 }
00430 
00431 static JSBool
00432 args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
00433              JSObject **objp)
00434 {
00435     JSStackFrame *fp;
00436     uintN slot;
00437     JSString *str;
00438     JSAtom *atom;
00439     intN tinyid;
00440     jsval value;
00441 
00442     *objp = NULL;
00443     fp = (JSStackFrame *)
00444          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
00445     if (!fp)
00446         return JS_TRUE;
00447     JS_ASSERT(fp->argsobj);
00448 
00449     if (JSVAL_IS_INT(id)) {
00450         slot = JSVAL_TO_INT(id);
00451         if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) {
00452             /* XXX ECMA specs DontEnum, contrary to other array-like objects */
00453             if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id),
00454                                    fp->argv[slot],
00455                                    args_getProperty, args_setProperty,
00456                                    JS_VERSION_IS_ECMA(cx)
00457                                    ? 0
00458                                    : JSPROP_ENUMERATE,
00459                                    NULL)) {
00460                 return JS_FALSE;
00461             }
00462             *objp = obj;
00463         }
00464     } else {
00465         str = JSVAL_TO_STRING(id);
00466         atom = cx->runtime->atomState.lengthAtom;
00467         if (str == ATOM_TO_STRING(atom)) {
00468             tinyid = ARGS_LENGTH;
00469             value = INT_TO_JSVAL(fp->argc);
00470         } else {
00471             atom = cx->runtime->atomState.calleeAtom;
00472             if (str == ATOM_TO_STRING(atom)) {
00473                 tinyid = ARGS_CALLEE;
00474                 value = fp->argv ? fp->argv[-2]
00475                                  : OBJECT_TO_JSVAL(fp->fun->object);
00476             } else {
00477                 atom = NULL;
00478 
00479                 /* Quell GCC overwarnings. */
00480                 tinyid = 0;
00481                 value = JSVAL_NULL;
00482             }
00483         }
00484 
00485         if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
00486             if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
00487                                          args_getProperty, args_setProperty, 0,
00488                                          SPROP_HAS_SHORTID, tinyid, NULL)) {
00489                 return JS_FALSE;
00490             }
00491             *objp = obj;
00492         }
00493     }
00494 
00495     return JS_TRUE;
00496 }
00497 
00498 static JSBool
00499 args_enumerate(JSContext *cx, JSObject *obj)
00500 {
00501     JSStackFrame *fp;
00502     JSObject *pobj;
00503     JSProperty *prop;
00504     uintN slot, argc;
00505 
00506     fp = (JSStackFrame *)
00507          JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
00508     if (!fp)
00509         return JS_TRUE;
00510     JS_ASSERT(fp->argsobj);
00511 
00512     /*
00513      * Trigger reflection with value snapshot in args_resolve using a series
00514      * of js_LookupProperty calls.  We handle length, callee, and the indexed
00515      * argument properties.  We know that args_resolve covers all these cases
00516      * and creates direct properties of obj, but that it may fail to resolve
00517      * length or callee if overridden.
00518      */
00519     if (!js_LookupProperty(cx, obj,
00520                            ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
00521                            &pobj, &prop)) {
00522         return JS_FALSE;
00523     }
00524     if (prop)
00525         OBJ_DROP_PROPERTY(cx, pobj, prop);
00526 
00527     if (!js_LookupProperty(cx, obj,
00528                            ATOM_TO_JSID(cx->runtime->atomState.calleeAtom),
00529                            &pobj, &prop)) {
00530         return JS_FALSE;
00531     }
00532     if (prop)
00533         OBJ_DROP_PROPERTY(cx, pobj, prop);
00534 
00535     argc = fp->argc;
00536     for (slot = 0; slot < argc; slot++) {
00537         if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop))
00538             return JS_FALSE;
00539         if (prop)
00540             OBJ_DROP_PROPERTY(cx, pobj, prop);
00541     }
00542     return JS_TRUE;
00543 }
00544 
00545 #if JS_HAS_GENERATORS
00546 /*
00547  * If a generator-iterator's arguments or call object escapes, it needs to
00548  * mark its generator object.
00549  */
00550 static uint32
00551 args_or_call_mark(JSContext *cx, JSObject *obj, void *arg)
00552 {
00553     JSStackFrame *fp;
00554 
00555     fp = JS_GetPrivate(cx, obj);
00556     if (fp && (fp->flags & JSFRAME_GENERATOR))
00557         GC_MARK(cx, FRAME_TO_GENERATOR(fp)->obj, "FRAME_TO_GENERATOR(fp)->obj");
00558     return 0;
00559 }
00560 #else
00561 # define args_or_call_mark NULL
00562 #endif
00563 
00564 /*
00565  * The Arguments class is not initialized via JS_InitClass, and must not be,
00566  * because its name is "Object".  Per ECMA, that causes instances of it to
00567  * delegate to the object named by Object.prototype.  It also ensures that
00568  * arguments.toString() returns "[object Object]".
00569  *
00570  * The JSClass functions below collaborate to lazily reflect and synchronize
00571  * actual argument values, argument count, and callee function object stored
00572  * in a JSStackFrame with their corresponding property values in the frame's
00573  * arguments object.
00574  */
00575 JSClass js_ArgumentsClass = {
00576     js_Object_str,
00577     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
00578     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
00579     JS_PropertyStub,    args_delProperty,
00580     args_getProperty,   args_setProperty,
00581     args_enumerate,     (JSResolveOp) args_resolve,
00582     JS_ConvertStub,     JS_FinalizeStub,
00583     NULL,               NULL,
00584     NULL,               NULL,
00585     NULL,               NULL,
00586     args_or_call_mark,  NULL
00587 };
00588 
00589 JSObject *
00590 js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
00591 {
00592     JSObject *callobj, *funobj;
00593 
00594     /* Create a call object for fp only if it lacks one. */
00595     JS_ASSERT(fp->fun);
00596     callobj = fp->callobj;
00597     if (callobj)
00598         return callobj;
00599     JS_ASSERT(fp->fun);
00600 
00601     /* The default call parent is its function's parent (static link). */
00602     if (!parent) {
00603         funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
00604         if (funobj)
00605             parent = OBJ_GET_PARENT(cx, funobj);
00606     }
00607 
00608     /* Create the call object and link it to its stack frame. */
00609     callobj = js_NewObject(cx, &js_CallClass, NULL, parent);
00610     if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
00611         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
00612         return NULL;
00613     }
00614     fp->callobj = callobj;
00615 
00616     /* Make callobj be the scope chain and the variables object. */
00617     JS_ASSERT(fp->scopeChain == parent);
00618     fp->scopeChain = callobj;
00619     fp->varobj = callobj;
00620     return callobj;
00621 }
00622 
00623 static JSBool
00624 call_enumerate(JSContext *cx, JSObject *obj);
00625 
00626 JSBool
00627 js_PutCallObject(JSContext *cx, JSStackFrame *fp)
00628 {
00629     JSObject *callobj;
00630     JSBool ok;
00631     jsid argsid;
00632     jsval aval;
00633 
00634     /*
00635      * Reuse call_enumerate here to reflect all actual args and vars into the
00636      * call object from fp.
00637      */
00638     callobj = fp->callobj;
00639     if (!callobj)
00640         return JS_TRUE;
00641     ok = call_enumerate(cx, callobj);
00642 
00643     /*
00644      * Get the arguments object to snapshot fp's actual argument values.
00645      */
00646     if (fp->argsobj) {
00647         argsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
00648         ok &= js_GetProperty(cx, callobj, argsid, &aval);
00649         ok &= js_SetProperty(cx, callobj, argsid, &aval);
00650         ok &= js_PutArgsObject(cx, fp);
00651     }
00652 
00653     /*
00654      * Clear the private pointer to fp, which is about to go away (js_Invoke).
00655      * Do this last because the call_enumerate and js_GetProperty calls above
00656      * need to follow the private slot to find fp.
00657      */
00658     ok &= JS_SetPrivate(cx, callobj, NULL);
00659     fp->callobj = NULL;
00660     return ok;
00661 }
00662 
00663 static JSPropertySpec call_props[] = {
00664     {js_arguments_str,  CALL_ARGUMENTS, JSPROP_PERMANENT,0,0},
00665     {"__callee__",      CALL_CALLEE,    0,0,0},
00666     {0,0,0,0,0}
00667 };
00668 
00669 static JSBool
00670 call_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00671 {
00672     JSStackFrame *fp;
00673     jsint slot;
00674 
00675     if (!JSVAL_IS_INT(id))
00676         return JS_TRUE;
00677     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00678     if (!fp)
00679         return JS_TRUE;
00680     JS_ASSERT(fp->fun);
00681 
00682     slot = JSVAL_TO_INT(id);
00683     switch (slot) {
00684       case CALL_ARGUMENTS:
00685         if (!TEST_OVERRIDE_BIT(fp, slot)) {
00686             JSObject *argsobj = js_GetArgsObject(cx, fp);
00687             if (!argsobj)
00688                 return JS_FALSE;
00689             *vp = OBJECT_TO_JSVAL(argsobj);
00690         }
00691         break;
00692 
00693       case CALL_CALLEE:
00694         if (!TEST_OVERRIDE_BIT(fp, slot))
00695             *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
00696         break;
00697 
00698       default:
00699         if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
00700             *vp = fp->argv[slot];
00701         break;
00702     }
00703     return JS_TRUE;
00704 }
00705 
00706 static JSBool
00707 call_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00708 {
00709     JSStackFrame *fp;
00710     jsint slot;
00711 
00712     if (!JSVAL_IS_INT(id))
00713         return JS_TRUE;
00714     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00715     if (!fp)
00716         return JS_TRUE;
00717     JS_ASSERT(fp->fun);
00718 
00719     slot = JSVAL_TO_INT(id);
00720     switch (slot) {
00721       case CALL_ARGUMENTS:
00722       case CALL_CALLEE:
00723         SET_OVERRIDE_BIT(fp, slot);
00724         break;
00725 
00726       default:
00727         if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
00728             fp->argv[slot] = *vp;
00729         break;
00730     }
00731     return JS_TRUE;
00732 }
00733 
00734 JSBool
00735 js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00736 {
00737     JSStackFrame *fp;
00738 
00739     JS_ASSERT(JSVAL_IS_INT(id));
00740     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00741     if (fp) {
00742         /* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
00743         if ((uintN)JSVAL_TO_INT(id) < fp->nvars)
00744             *vp = fp->vars[JSVAL_TO_INT(id)];
00745     }
00746     return JS_TRUE;
00747 }
00748 
00749 JSBool
00750 js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00751 {
00752     JSStackFrame *fp;
00753 
00754     JS_ASSERT(JSVAL_IS_INT(id));
00755     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00756     if (fp) {
00757         /* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
00758         jsint slot = JSVAL_TO_INT(id);
00759         if ((uintN)slot < fp->nvars)
00760             fp->vars[slot] = *vp;
00761     }
00762     return JS_TRUE;
00763 }
00764 
00765 static JSBool
00766 call_enumerate(JSContext *cx, JSObject *obj)
00767 {
00768     JSStackFrame *fp;
00769     JSObject *funobj, *pobj;
00770     JSScope *scope;
00771     JSScopeProperty *sprop, *cprop;
00772     JSPropertyOp getter;
00773     jsval *vec;
00774     JSAtom *atom;
00775     JSProperty *prop;
00776 
00777     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00778     if (!fp)
00779         return JS_TRUE;
00780 
00781     /*
00782      * Do not enumerate a cloned function object at fp->argv[-2], it may have
00783      * gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
00784      * the clone's prototype property).  We must enumerate the function object
00785      * that was decorated with parameter and local variable properties by the
00786      * compiler when the compiler created fp->fun, namely fp->fun->object.
00787      *
00788      * Contrast with call_resolve, where we prefer fp->argv[-2], because we'll
00789      * use js_LookupProperty to find any overridden properties in that object,
00790      * if it was a mutated clone; and if not, we will search its prototype,
00791      * fp->fun->object, to find compiler-created params and locals.
00792      */
00793     funobj = fp->fun->object;
00794     if (!funobj)
00795         return JS_TRUE;
00796 
00797     /*
00798      * Reflect actual args from fp->argv for formal parameters, and local vars
00799      * and functions in fp->vars for declared variables and nested-at-top-level
00800      * local functions.
00801      */
00802     scope = OBJ_SCOPE(funobj);
00803     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
00804         getter = sprop->getter;
00805         if (getter == js_GetArgument)
00806             vec = fp->argv;
00807         else if (getter == js_GetLocalVariable)
00808             vec = fp->vars;
00809         else
00810             continue;
00811 
00812         /* Trigger reflection by looking up the unhidden atom for sprop->id. */
00813         JS_ASSERT(JSID_IS_ATOM(sprop->id));
00814         atom = JSID_TO_ATOM(sprop->id);
00815         JS_ASSERT(atom->flags & ATOM_HIDDEN);
00816         atom = atom->entry.value;
00817 
00818         if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
00819             return JS_FALSE;
00820 
00821         /*
00822          * If we found the property in a different object, don't try sticking
00823          * it into wrong slots vector. This can occur because we have a mutable
00824          * __proto__ slot, and cloned function objects rely on their __proto__
00825          * to delegate to the object that contains the var and arg properties.
00826          */
00827         if (!prop || pobj != obj) {
00828             if (prop)
00829                 OBJ_DROP_PROPERTY(cx, pobj, prop);
00830             continue;
00831         }
00832         cprop = (JSScopeProperty *)prop;
00833         LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[(uint16) sprop->shortid]);
00834         OBJ_DROP_PROPERTY(cx, obj, prop);
00835     }
00836 
00837     return JS_TRUE;
00838 }
00839 
00840 static JSBool
00841 call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
00842              JSObject **objp)
00843 {
00844     JSStackFrame *fp;
00845     JSObject *funobj;
00846     JSString *str;
00847     JSAtom *atom;
00848     JSObject *obj2;
00849     JSProperty *prop;
00850     JSScopeProperty *sprop;
00851     JSPropertyOp getter, setter;
00852     uintN attrs, slot, nslots, spflags;
00853     jsval *vp, value;
00854     intN shortid;
00855 
00856     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00857     if (!fp)
00858         return JS_TRUE;
00859     JS_ASSERT(fp->fun);
00860 
00861     if (!JSVAL_IS_STRING(id))
00862         return JS_TRUE;
00863 
00864     funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
00865     if (!funobj)
00866         return JS_TRUE;
00867     JS_ASSERT((JSFunction *) JS_GetPrivate(cx, funobj) == fp->fun);
00868 
00869     str = JSVAL_TO_STRING(id);
00870     atom = js_AtomizeString(cx, str, 0);
00871     if (!atom)
00872         return JS_FALSE;
00873     if (!js_LookupHiddenProperty(cx, funobj, ATOM_TO_JSID(atom), &obj2, &prop))
00874         return JS_FALSE;
00875 
00876     if (prop) {
00877         if (!OBJ_IS_NATIVE(obj2)) {
00878             OBJ_DROP_PROPERTY(cx, obj2, prop);
00879             return JS_TRUE;
00880         }
00881 
00882         sprop = (JSScopeProperty *) prop;
00883         getter = sprop->getter;
00884         attrs = sprop->attrs & ~JSPROP_SHARED;
00885         slot = (uintN) sprop->shortid;
00886         OBJ_DROP_PROPERTY(cx, obj2, prop);
00887 
00888         /* Ensure we found an arg or var property for the same function. */
00889         if ((sprop->flags & SPROP_IS_HIDDEN) &&
00890             (obj2 == funobj ||
00891              (JSFunction *) JS_GetPrivate(cx, obj2) == fp->fun)) {
00892             if (getter == js_GetArgument) {
00893                 vp = fp->argv;
00894                 nslots = JS_MAX(fp->argc, fp->fun->nargs);
00895                 getter = setter = NULL;
00896             } else {
00897                 JS_ASSERT(getter == js_GetLocalVariable);
00898                 vp = fp->vars;
00899                 nslots = fp->nvars;
00900                 getter = js_GetCallVariable;
00901                 setter = js_SetCallVariable;
00902             }
00903             if (slot < nslots) {
00904                 value = vp[slot];
00905                 spflags = SPROP_HAS_SHORTID;
00906                 shortid = (intN) slot;
00907             } else {
00908                 value = JSVAL_VOID;
00909                 spflags = 0;
00910                 shortid = 0;
00911             }
00912             if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
00913                                          getter, setter, attrs,
00914                                          spflags, shortid, NULL)) {
00915                 return JS_FALSE;
00916             }
00917             *objp = obj;
00918         }
00919     }
00920 
00921     return JS_TRUE;
00922 }
00923 
00924 static JSBool
00925 call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
00926 {
00927     JSStackFrame *fp;
00928 
00929     if (type == JSTYPE_FUNCTION) {
00930         fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
00931         if (fp) {
00932             JS_ASSERT(fp->fun);
00933             *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
00934         }
00935     }
00936     return JS_TRUE;
00937 }
00938 
00939 JSClass js_CallClass = {
00940     js_Call_str,
00941     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
00942     JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
00943     JS_PropertyStub,    JS_PropertyStub,
00944     call_getProperty,   call_setProperty,
00945     call_enumerate,     (JSResolveOp)call_resolve,
00946     call_convert,       JS_FinalizeStub,
00947     NULL,               NULL,
00948     NULL,               NULL,
00949     NULL,               NULL,
00950     args_or_call_mark,  NULL,
00951 };
00952 
00953 /*
00954  * ECMA-262 specifies that length is a property of function object instances,
00955  * but we can avoid that space cost by delegating to a prototype property that
00956  * is JSPROP_PERMANENT and JSPROP_SHARED.  Each fun_getProperty call computes
00957  * a fresh length value based on the arity of the individual function object's
00958  * private data.
00959  *
00960  * The extensions below other than length, i.e., the ones not in ECMA-262,
00961  * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
00962  * with ECMA we must allow a delegating object to override them.
00963  */
00964 #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
00965 
00966 static JSPropertySpec function_props[] = {
00967     {js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT,  0,0},
00968     {js_arity_str,     FUN_ARITY,      JSPROP_PERMANENT,  0,0},
00969     {js_caller_str,    FUN_CALLER,     JSPROP_PERMANENT,  0,0},
00970     {js_length_str,    ARGS_LENGTH,    LENGTH_PROP_ATTRS, 0,0},
00971     {js_name_str,      FUN_NAME,       JSPROP_PERMANENT,  0,0},
00972     {0,0,0,0,0}
00973 };
00974 
00975 static JSBool
00976 fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00977 {
00978     jsint slot;
00979     JSFunction *fun;
00980     JSStackFrame *fp;
00981 
00982     if (!JSVAL_IS_INT(id))
00983         return JS_TRUE;
00984     slot = JSVAL_TO_INT(id);
00985 
00986     /*
00987      * Loop because getter and setter can be delegated from another class,
00988      * but loop only for ARGS_LENGTH because we must pretend that f.length
00989      * is in each function instance f, per ECMA-262, instead of only in the
00990      * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
00991      * to make it appear so).
00992      *
00993      * This code couples tightly to the attributes for the function_props[]
00994      * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper.
00995      *
00996      * It's important to allow delegating objects, even though they inherit
00997      * this getter (fun_getProperty), to override arguments, arity, caller,
00998      * and name.  If we didn't return early for slot != ARGS_LENGTH, we would
00999      * clobber *vp with the native property value, instead of letting script
01000      * override that value in delegating objects.
01001      *
01002      * Note how that clobbering is what simulates JSPROP_READONLY for all of
01003      * the non-standard properties when the directly addressed object (obj)
01004      * is a function object (i.e., when this loop does not iterate).
01005      */
01006     while (!(fun = (JSFunction *)
01007                    JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
01008         if (slot != ARGS_LENGTH)
01009             return JS_TRUE;
01010         obj = OBJ_GET_PROTO(cx, obj);
01011         if (!obj)
01012             return JS_TRUE;
01013     }
01014 
01015     /* Find fun's top-most activation record. */
01016     for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
01017          fp = fp->down) {
01018         continue;
01019     }
01020 
01021     switch (slot) {
01022       case CALL_ARGUMENTS:
01023         /* Warn if strict about f.arguments or equivalent unqualified uses. */
01024         if (!JS_ReportErrorFlagsAndNumber(cx,
01025                                           JSREPORT_WARNING | JSREPORT_STRICT,
01026                                           js_GetErrorMessage, NULL,
01027                                           JSMSG_DEPRECATED_USAGE,
01028                                           js_arguments_str)) {
01029             return JS_FALSE;
01030         }
01031         if (fp) {
01032             if (!js_GetArgsValue(cx, fp, vp))
01033                 return JS_FALSE;
01034         } else {
01035             *vp = JSVAL_NULL;
01036         }
01037         break;
01038 
01039       case ARGS_LENGTH:
01040       case FUN_ARITY:
01041             *vp = INT_TO_JSVAL((jsint)fun->nargs);
01042         break;
01043 
01044       case FUN_NAME:
01045         *vp = fun->atom
01046               ? ATOM_KEY(fun->atom)
01047               : STRING_TO_JSVAL(cx->runtime->emptyString);
01048         break;
01049 
01050       case FUN_CALLER:
01051         while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down)
01052             fp = fp->down;
01053         if (fp && fp->down && fp->down->fun && fp->down->argv)
01054             *vp = fp->down->argv[-2];
01055         else
01056             *vp = JSVAL_NULL;
01057         if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
01058             id = ATOM_KEY(cx->runtime->atomState.callerAtom);
01059             if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
01060                 return JS_FALSE;
01061         }
01062         break;
01063 
01064       default:
01065         /* XXX fun[0] and fun.arguments[0] are equivalent. */
01066         if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
01067             *vp = fp->argv[slot];
01068         break;
01069     }
01070 
01071     return JS_TRUE;
01072 }
01073 
01074 static JSBool
01075 fun_enumerate(JSContext *cx, JSObject *obj)
01076 {
01077     jsid prototypeId;
01078     JSObject *pobj;
01079     JSProperty *prop;
01080 
01081     prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
01082     if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop))
01083         return JS_FALSE;
01084     if (prop)
01085         OBJ_DROP_PROPERTY(cx, pobj, prop);
01086     return JS_TRUE;
01087 }
01088 
01089 static JSBool
01090 fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
01091             JSObject **objp)
01092 {
01093     JSFunction *fun;
01094     JSString *str;
01095     JSAtom *prototypeAtom;
01096 
01097     /*
01098      * No need to reflect fun.prototype in 'fun.prototype = ...' or in an
01099      * unqualified reference to prototype, which the emitter looks up as a
01100      * hidden atom when attempting to bind to a formal parameter or local
01101      * variable slot.
01102      */
01103     if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_HIDDEN))
01104         return JS_TRUE;
01105 
01106     if (!JSVAL_IS_STRING(id))
01107         return JS_TRUE;
01108 
01109     /* No valid function object should lack private data, but check anyway. */
01110     fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
01111     if (!fun || !fun->object)
01112         return JS_TRUE;
01113 
01114     /*
01115      * Ok, check whether id is 'prototype' and bootstrap the function object's
01116      * prototype property.
01117      */
01118     str = JSVAL_TO_STRING(id);
01119     prototypeAtom = cx->runtime->atomState.classPrototypeAtom;
01120     if (str == ATOM_TO_STRING(prototypeAtom)) {
01121         JSObject *proto, *parentProto;
01122         jsval pval;
01123 
01124         proto = parentProto = NULL;
01125         if (fun->object != obj && fun->object) {
01126             /*
01127              * Clone of a function: make its prototype property value have the
01128              * same class as the clone-parent's prototype.
01129              */
01130             if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(prototypeAtom),
01131                                   &pval)) {
01132                 return JS_FALSE;
01133             }
01134             if (!JSVAL_IS_PRIMITIVE(pval)) {
01135                 /*
01136                  * We are about to allocate a new object, so hack the newborn
01137                  * root until then to protect pval in case it is figuratively
01138                  * up in the air, with no strong refs protecting it.
01139                  */
01140                 cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(pval);
01141                 parentProto = JSVAL_TO_OBJECT(pval);
01142             }
01143         }
01144 
01145         /*
01146          * Beware of the wacky case of a user function named Object -- trying
01147          * to find a prototype for that will recur back here _ad perniciem_.
01148          */
01149         if (!parentProto && fun->atom == CLASS_ATOM(cx, Object))
01150             return JS_TRUE;
01151 
01152         /*
01153          * If resolving "prototype" in a clone, clone the parent's prototype.
01154          * Pass the constructor's (obj's) parent as the prototype parent, to
01155          * avoid defaulting to parentProto.constructor.__parent__.
01156          */
01157         proto = js_NewObject(cx, &js_ObjectClass, parentProto,
01158                              OBJ_GET_PARENT(cx, obj));
01159         if (!proto)
01160             return JS_FALSE;
01161 
01162         /*
01163          * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
01164          * user-defined functions, but DontEnum | ReadOnly | DontDelete for
01165          * native "system" constructors such as Object or Function.  So lazily
01166          * set the former here in fun_resolve, but eagerly define the latter
01167          * in JS_InitClass, with the right attributes.
01168          */
01169         if (!js_SetClassPrototype(cx, obj, proto,
01170                                   JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
01171             cx->weakRoots.newborn[GCX_OBJECT] = NULL;
01172             return JS_FALSE;
01173         }
01174         *objp = obj;
01175     }
01176 
01177     return JS_TRUE;
01178 }
01179 
01180 static JSBool
01181 fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
01182 {
01183     switch (type) {
01184       case JSTYPE_FUNCTION:
01185         *vp = OBJECT_TO_JSVAL(obj);
01186         return JS_TRUE;
01187       default:
01188         return js_TryValueOf(cx, obj, type, vp);
01189     }
01190 }
01191 
01192 static void
01193 fun_finalize(JSContext *cx, JSObject *obj)
01194 {
01195     JSFunction *fun;
01196     JSScript *script;
01197 
01198     /* No valid function object should lack private data, but check anyway. */
01199     fun = (JSFunction *) JS_GetPrivate(cx, obj);
01200     if (!fun)
01201         return;
01202     if (fun->object == obj)
01203         fun->object = NULL;
01204 
01205     /* Null-check required since the parser sets interpreted very early. */
01206     if (FUN_INTERPRETED(fun) && fun->u.i.script &&
01207         js_IsAboutToBeFinalized(cx, fun))
01208     {
01209         script = fun->u.i.script;
01210         fun->u.i.script = NULL;
01211         js_DestroyScript(cx, script);
01212     }
01213 }
01214 
01215 #if JS_HAS_XDR
01216 
01217 #include "jsxdrapi.h"
01218 
01219 enum {
01220     JSXDR_FUNARG = 1,
01221     JSXDR_FUNVAR = 2,
01222     JSXDR_FUNCONST = 3
01223 };
01224 
01225 /* XXX store parent and proto, if defined */
01226 static JSBool
01227 fun_xdrObject(JSXDRState *xdr, JSObject **objp)
01228 {
01229     JSContext *cx;
01230     JSFunction *fun;
01231     uint32 nullAtom;            /* flag to indicate if fun->atom is NULL */
01232     JSTempValueRooter tvr;
01233     uint32 flagsword;           /* originally only flags was JS_XDRUint8'd */
01234     uint16 extraUnused;         /* variable for no longer used field */
01235     JSAtom *propAtom;
01236     JSScopeProperty *sprop;
01237     uint32 userid;              /* NB: holds a signed int-tagged jsval */
01238     uintN i, n, dupflag;
01239     uint32 type;
01240     JSBool ok;
01241 #ifdef DEBUG
01242     uintN nvars = 0, nargs = 0;
01243 #endif
01244 
01245     cx = xdr->cx;
01246     if (xdr->mode == JSXDR_ENCODE) {
01247         /*
01248          * No valid function object should lack private data, but fail soft
01249          * (return true, no error report) in case one does due to API pilot
01250          * or internal error.
01251          */
01252         fun = (JSFunction *) JS_GetPrivate(cx, *objp);
01253         if (!fun)
01254             return JS_TRUE;
01255         if (!FUN_INTERPRETED(fun)) {
01256             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01257                                  JSMSG_NOT_SCRIPTED_FUNCTION,
01258                                  JS_GetFunctionName(fun));
01259             return JS_FALSE;
01260         }
01261         nullAtom = !fun->atom;
01262         flagsword = ((uint32)fun->u.i.nregexps << 16) | fun->flags;
01263         extraUnused = 0;
01264     } else {
01265         fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
01266         if (!fun)
01267             return JS_FALSE;
01268     }
01269 
01270     /* From here on, control flow must flow through label out. */
01271     JS_PUSH_TEMP_ROOT_OBJECT(cx, fun->object, &tvr);
01272     ok = JS_TRUE;
01273 
01274     if (!JS_XDRUint32(xdr, &nullAtom))
01275         goto bad;
01276     if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))
01277         goto bad;
01278 
01279     if (!JS_XDRUint16(xdr, &fun->nargs) ||
01280         !JS_XDRUint16(xdr, &extraUnused) ||
01281         !JS_XDRUint16(xdr, &fun->u.i.nvars) ||
01282         !JS_XDRUint32(xdr, &flagsword)) {
01283         goto bad;
01284     }
01285 
01286     /* Assert that all previous writes of extraUnused were writes of 0. */
01287     JS_ASSERT(extraUnused == 0);
01288 
01289     /* do arguments and local vars */
01290     if (fun->object) {
01291         n = fun->nargs + fun->u.i.nvars;
01292         if (xdr->mode == JSXDR_ENCODE) {
01293             JSScope *scope;
01294             JSScopeProperty **spvec, *auto_spvec[8];
01295             void *mark;
01296 
01297             if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) {
01298                 spvec = auto_spvec;
01299                 mark = NULL;
01300             } else {
01301                 mark = JS_ARENA_MARK(&cx->tempPool);
01302                 JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool,
01303                                        n * sizeof(JSScopeProperty *));
01304                 if (!spvec) {
01305                     JS_ReportOutOfMemory(cx);
01306                     goto bad;
01307                 }
01308             }
01309             scope = OBJ_SCOPE(fun->object);
01310             for (sprop = SCOPE_LAST_PROP(scope); sprop;
01311                  sprop = sprop->parent) {
01312                 if (sprop->getter == js_GetArgument) {
01313                     JS_ASSERT(nargs++ <= fun->nargs);
01314                     spvec[sprop->shortid] = sprop;
01315                 } else if (sprop->getter == js_GetLocalVariable) {
01316                     JS_ASSERT(nvars++ <= fun->u.i.nvars);
01317                     spvec[fun->nargs + sprop->shortid] = sprop;
01318                 }
01319             }
01320             for (i = 0; i < n; i++) {
01321                 sprop = spvec[i];
01322                 JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
01323                 type = (i < fun->nargs)
01324                        ? JSXDR_FUNARG
01325                        : (sprop->attrs & JSPROP_READONLY)
01326                        ? JSXDR_FUNCONST
01327                        : JSXDR_FUNVAR;
01328                 userid = INT_TO_JSVAL(sprop->shortid);
01329                 propAtom = JSID_TO_ATOM(sprop->id);
01330                 if (!JS_XDRUint32(xdr, &type) ||
01331                     !JS_XDRUint32(xdr, &userid) ||
01332                     !js_XDRCStringAtom(xdr, &propAtom)) {
01333                     if (mark)
01334                         JS_ARENA_RELEASE(&cx->tempPool, mark);
01335                     goto bad;
01336                 }
01337             }
01338             if (mark)
01339                 JS_ARENA_RELEASE(&cx->tempPool, mark);
01340         } else {
01341             JSPropertyOp getter, setter;
01342 
01343             for (i = n; i != 0; i--) {
01344                 uintN attrs = JSPROP_PERMANENT;
01345 
01346                 if (!JS_XDRUint32(xdr, &type) ||
01347                     !JS_XDRUint32(xdr, &userid) ||
01348                     !js_XDRCStringAtom(xdr, &propAtom)) {
01349                     goto bad;
01350                 }
01351                 JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
01352                           type == JSXDR_FUNCONST);
01353                 if (type == JSXDR_FUNARG) {
01354                     getter = js_GetArgument;
01355                     setter = js_SetArgument;
01356                     JS_ASSERT(nargs++ <= fun->nargs);
01357                 } else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) {
01358                     getter = js_GetLocalVariable;
01359                     setter = js_SetLocalVariable;
01360                     if (type == JSXDR_FUNCONST)
01361                         attrs |= JSPROP_READONLY;
01362                     JS_ASSERT(nvars++ <= fun->u.i.nvars);
01363                 } else {
01364                     getter = NULL;
01365                     setter = NULL;
01366                 }
01367 
01368                 /* Flag duplicate argument if atom is bound in fun->object. */
01369                 dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object),
01370                                              ATOM_TO_JSID(propAtom))
01371                           ? SPROP_IS_DUPLICATE
01372                           : 0;
01373 
01374                 if (!js_AddHiddenProperty(cx, fun->object,
01375                                           ATOM_TO_JSID(propAtom),
01376                                           getter, setter, SPROP_INVALID_SLOT,
01377                                           attrs | JSPROP_SHARED,
01378                                           dupflag | SPROP_HAS_SHORTID,
01379                                           JSVAL_TO_INT(userid))) {
01380                     goto bad;
01381                 }
01382             }
01383         }
01384     }
01385 
01386     if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
01387         goto bad;
01388 
01389     if (xdr->mode == JSXDR_DECODE) {
01390         fun->flags = (uint16) flagsword | JSFUN_INTERPRETED;
01391         fun->u.i.nregexps = (uint16) (flagsword >> 16);
01392 
01393         *objp = fun->object;
01394         js_CallNewScriptHook(cx, fun->u.i.script, fun);
01395     }
01396 
01397 out:
01398     JS_POP_TEMP_ROOT(cx, &tvr);
01399     return ok;
01400 
01401 bad:
01402     ok = JS_FALSE;
01403     goto out;
01404 }
01405 
01406 #else  /* !JS_HAS_XDR */
01407 
01408 #define fun_xdrObject NULL
01409 
01410 #endif /* !JS_HAS_XDR */
01411 
01412 /*
01413  * [[HasInstance]] internal method for Function objects: fetch the .prototype
01414  * property of its 'this' parameter, and walks the prototype chain of v (only
01415  * if v is an object) returning true if .prototype is found.
01416  */
01417 static JSBool
01418 fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
01419 {
01420     jsval pval;
01421     JSString *str;
01422 
01423     if (!OBJ_GET_PROPERTY(cx, obj,
01424                           ATOM_TO_JSID(cx->runtime->atomState
01425                                        .classPrototypeAtom),
01426                           &pval)) {
01427         return JS_FALSE;
01428     }
01429 
01430     if (JSVAL_IS_PRIMITIVE(pval)) {
01431         /*
01432          * Throw a runtime error if instanceof is called on a function that
01433          * has a non-object as its .prototype value.
01434          */
01435         str = js_DecompileValueGenerator(cx, -1, OBJECT_TO_JSVAL(obj), NULL);
01436         if (str) {
01437             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01438                                  JSMSG_BAD_PROTOTYPE, JS_GetStringBytes(str));
01439         }
01440         return JS_FALSE;
01441     }
01442 
01443     return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
01444 }
01445 
01446 static uint32
01447 fun_mark(JSContext *cx, JSObject *obj, void *arg)
01448 {
01449     JSFunction *fun;
01450 
01451     fun = (JSFunction *) JS_GetPrivate(cx, obj);
01452     if (fun) {
01453         GC_MARK(cx, fun, "private");
01454         if (fun->atom)
01455             GC_MARK_ATOM(cx, fun->atom);
01456         if (FUN_INTERPRETED(fun) && fun->u.i.script)
01457             js_MarkScript(cx, fun->u.i.script);
01458     }
01459     return 0;
01460 }
01461 
01462 static uint32
01463 fun_reserveSlots(JSContext *cx, JSObject *obj)
01464 {
01465     JSFunction *fun;
01466 
01467     fun = (JSFunction *) JS_GetPrivate(cx, obj);
01468     return (fun && FUN_INTERPRETED(fun)) ? fun->u.i.nregexps : 0;
01469 }
01470 
01471 /*
01472  * Reserve two slots in all function objects for XPConnect.  Note that this
01473  * does not bloat every instance, only those on which reserved slots are set,
01474  * and those on which ad-hoc properties are defined.
01475  */
01476 JS_FRIEND_DATA(JSClass) js_FunctionClass = {
01477     js_Function_str,
01478     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) |
01479     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
01480     JS_PropertyStub,  JS_PropertyStub,
01481     fun_getProperty,  JS_PropertyStub,
01482     fun_enumerate,    (JSResolveOp)fun_resolve,
01483     fun_convert,      fun_finalize,
01484     NULL,             NULL,
01485     NULL,             NULL,
01486     fun_xdrObject,    fun_hasInstance,
01487     fun_mark,         fun_reserveSlots
01488 };
01489 
01490 JSBool
01491 js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
01492                 uintN argc, jsval *argv, jsval *rval)
01493 {
01494     jsval fval;
01495     JSFunction *fun;
01496     JSString *str;
01497 
01498     if (!argv) {
01499         JS_ASSERT(JS_ObjectIsFunction(cx, obj));
01500     } else {
01501         fval = argv[-1];
01502         if (!VALUE_IS_FUNCTION(cx, fval)) {
01503             /*
01504              * If we don't have a function to start off with, try converting
01505              * the object to a function.  If that doesn't work, complain.
01506              */
01507             if (JSVAL_IS_OBJECT(fval)) {
01508                 obj = JSVAL_TO_OBJECT(fval);
01509                 if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
01510                                                      &fval)) {
01511                     return JS_FALSE;
01512                 }
01513                 argv[-1] = fval;
01514             }
01515             if (!VALUE_IS_FUNCTION(cx, fval)) {
01516                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01517                                      JSMSG_INCOMPATIBLE_PROTO,
01518                                      js_Function_str, js_toString_str,
01519                                      JS_GetTypeName(cx,
01520                                                     JS_TypeOfValue(cx, fval)));
01521                 return JS_FALSE;
01522             }
01523         }
01524 
01525         obj = JSVAL_TO_OBJECT(fval);
01526     }
01527 
01528     fun = (JSFunction *) JS_GetPrivate(cx, obj);
01529     if (!fun)
01530         return JS_TRUE;
01531     if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
01532         return JS_FALSE;
01533     str = JS_DecompileFunction(cx, fun, (uintN)indent);
01534     if (!str)
01535         return JS_FALSE;
01536     *rval = STRING_TO_JSVAL(str);
01537     return JS_TRUE;
01538 }
01539 
01540 static JSBool
01541 fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01542 {
01543     return js_fun_toString(cx, obj, 0, argc, argv, rval);
01544 }
01545 
01546 #if JS_HAS_TOSOURCE
01547 static JSBool
01548 fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01549 {
01550     return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);
01551 }
01552 #endif
01553 
01554 static const char call_str[] = "call";
01555 
01556 static JSBool
01557 fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01558 {
01559     jsval fval, *sp, *oldsp;
01560     JSString *str;
01561     void *mark;
01562     uintN i;
01563     JSStackFrame *fp;
01564     JSBool ok;
01565 
01566     if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
01567         return JS_FALSE;
01568     fval = argv[-1];
01569 
01570     if (!VALUE_IS_FUNCTION(cx, fval)) {
01571         str = JS_ValueToString(cx, fval);
01572         if (str) {
01573             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01574                                  JSMSG_INCOMPATIBLE_PROTO,
01575                                  js_Function_str, call_str,
01576                                  JS_GetStringBytes(str));
01577         }
01578         return JS_FALSE;
01579     }
01580 
01581     if (argc == 0) {
01582         /* Call fun with its global object as the 'this' param if no args. */
01583         obj = NULL;
01584     } else {
01585         /* Otherwise convert the first arg to 'this' and skip over it. */
01586         if (!JSVAL_IS_PRIMITIVE(argv[0]))
01587             obj = JSVAL_TO_OBJECT(argv[0]);
01588         else if (!js_ValueToObject(cx, argv[0], &obj))
01589             return JS_FALSE;
01590         argc--;
01591         argv++;
01592     }
01593 
01594     /* Allocate stack space for fval, obj, and the args. */
01595     sp = js_AllocStack(cx, 2 + argc, &mark);
01596     if (!sp)
01597         return JS_FALSE;
01598 
01599     /* Push fval, obj, and the args. */
01600     *sp++ = fval;
01601     *sp++ = OBJECT_TO_JSVAL(obj);
01602     for (i = 0; i < argc; i++)
01603         *sp++ = argv[i];
01604 
01605     /* Lift current frame to include the args and do the call. */
01606     fp = cx->fp;
01607     oldsp = fp->sp;
01608     fp->sp = sp;
01609     ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
01610 
01611     /* Store rval and pop stack back to our frame's sp. */
01612     *rval = fp->sp[-1];
01613     fp->sp = oldsp;
01614     js_FreeStack(cx, mark);
01615     return ok;
01616 }
01617 
01618 static JSBool
01619 fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01620 {
01621     jsval fval, *sp, *oldsp;
01622     JSString *str;
01623     JSObject *aobj;
01624     jsuint length;
01625     JSBool arraylike, ok;
01626     void *mark;
01627     uintN i;
01628     JSStackFrame *fp;
01629 
01630     if (argc == 0) {
01631         /* Will get globalObject as 'this' and no other arguments. */
01632         return fun_call(cx, obj, argc, argv, rval);
01633     }
01634 
01635     if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
01636         return JS_FALSE;
01637     fval = argv[-1];
01638 
01639     if (!VALUE_IS_FUNCTION(cx, fval)) {
01640         str = JS_ValueToString(cx, fval);
01641         if (str) {
01642             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01643                                  JSMSG_INCOMPATIBLE_PROTO,
01644                                  js_Function_str, "apply",
01645                                  JS_GetStringBytes(str));
01646         }
01647         return JS_FALSE;
01648     }
01649 
01650     /* Quell GCC overwarnings. */
01651     aobj = NULL;
01652     length = 0;
01653 
01654     if (argc >= 2) {
01655         /* If the 2nd arg is null or void, call the function with 0 args. */
01656         if (JSVAL_IS_NULL(argv[1]) || JSVAL_IS_VOID(argv[1])) {
01657             argc = 0;
01658         } else {
01659             /* The second arg must be an array (or arguments object). */
01660             arraylike = JS_FALSE;
01661             if (!JSVAL_IS_PRIMITIVE(argv[1])) {
01662                 aobj = JSVAL_TO_OBJECT(argv[1]);
01663                 if (!js_IsArrayLike(cx, aobj, &arraylike, &length))
01664                     return JS_FALSE;
01665             }
01666             if (!arraylike) {
01667                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01668                                      JSMSG_BAD_APPLY_ARGS, "apply");
01669                 return JS_FALSE;
01670             }
01671         }
01672     }
01673 
01674     /* Convert the first arg to 'this' and skip over it. */
01675     if (!JSVAL_IS_PRIMITIVE(argv[0]))
01676         obj = JSVAL_TO_OBJECT(argv[0]);
01677     else if (!js_ValueToObject(cx, argv[0], &obj))
01678         return JS_FALSE;
01679 
01680     /* Allocate stack space for fval, obj, and the args. */
01681     argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
01682     sp = js_AllocStack(cx, 2 + argc, &mark);
01683     if (!sp)
01684         return JS_FALSE;
01685 
01686     /* Push fval, obj, and aobj's elements as args. */
01687     *sp++ = fval;
01688     *sp++ = OBJECT_TO_JSVAL(obj);
01689     for (i = 0; i < argc; i++) {
01690         ok = JS_GetElement(cx, aobj, (jsint)i, sp);
01691         if (!ok)
01692             goto out;
01693         sp++;
01694     }
01695 
01696     /* Lift current frame to include the args and do the call. */
01697     fp = cx->fp;
01698     oldsp = fp->sp;
01699     fp->sp = sp;
01700     ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
01701 
01702     /* Store rval and pop stack back to our frame's sp. */
01703     *rval = fp->sp[-1];
01704     fp->sp = oldsp;
01705 out:
01706     js_FreeStack(cx, mark);
01707     return ok;
01708 }
01709 
01710 #ifdef NARCISSUS
01711 static JSBool
01712 fun_applyConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
01713                      jsval *rval)
01714 {
01715     JSObject *aobj;
01716     uintN length, i;
01717     void *mark;
01718     jsval *sp, *newsp, *oldsp;
01719     JSStackFrame *fp;
01720     JSBool ok;
01721 
01722     if (JSVAL_IS_PRIMITIVE(argv[0]) ||
01723         (aobj = JSVAL_TO_OBJECT(argv[0]),
01724          OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass &&
01725          OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) {
01726         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01727                              JSMSG_BAD_APPLY_ARGS, "__applyConstruct__");
01728         return JS_FALSE;
01729     }
01730 
01731     if (!js_GetLengthProperty(cx, aobj, &length))
01732         return JS_FALSE;
01733 
01734     if (length >= ARRAY_INIT_LIMIT)
01735         length = ARRAY_INIT_LIMIT - 1;
01736     newsp = sp = js_AllocStack(cx, 2 + length, &mark);
01737     if (!sp)
01738         return JS_FALSE;
01739 
01740     fp = cx->fp;
01741     oldsp = fp->sp;
01742     *sp++ = OBJECT_TO_JSVAL(obj);
01743     *sp++ = JSVAL_NULL; /* This is filled automagically. */
01744     for (i = 0; i < length; i++) {
01745         ok = JS_GetElement(cx, aobj, (jsint)i, sp);
01746         if (!ok)
01747             goto out;
01748         sp++;
01749     }
01750 
01751     oldsp = fp->sp;
01752     fp->sp = sp;
01753     ok = js_InvokeConstructor(cx, newsp, length);
01754 
01755     *rval = fp->sp[-1];
01756     fp->sp = oldsp;
01757 out:
01758     js_FreeStack(cx, mark);
01759     return ok;
01760 }
01761 #endif
01762 
01763 static JSFunctionSpec function_methods[] = {
01764 #if JS_HAS_TOSOURCE
01765     {js_toSource_str,   fun_toSource,   0,0,0},
01766 #endif
01767     {js_toString_str,   fun_toString,   1,0,0},
01768     {"apply",           fun_apply,      2,0,0},
01769     {call_str,          fun_call,       1,0,0},
01770 #ifdef NARCISSUS
01771     {"__applyConstructor__", fun_applyConstructor, 1,0,0},
01772 #endif
01773     {0,0,0,0,0}
01774 };
01775 
01776 JSBool
01777 js_IsIdentifier(JSString *str)
01778 {
01779     size_t length;
01780     jschar c, *chars, *end, *s;
01781 
01782     length = JSSTRING_LENGTH(str);
01783     if (length == 0)
01784         return JS_FALSE;
01785     chars = JSSTRING_CHARS(str);
01786     c = *chars;
01787     if (!JS_ISIDSTART(c))
01788         return JS_FALSE;
01789     end = chars + length;
01790     for (s = chars + 1; s != end; ++s) {
01791         c = *s;
01792         if (!JS_ISIDENT(c))
01793             return JS_FALSE;
01794     }
01795     return !js_IsKeyword(chars, length);
01796 }
01797 
01798 static JSBool
01799 Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01800 {
01801     JSStackFrame *fp, *caller;
01802     JSFunction *fun;
01803     JSObject *parent;
01804     uintN i, n, lineno, dupflag;
01805     JSAtom *atom;
01806     const char *filename;
01807     JSObject *obj2;
01808     JSProperty *prop;
01809     JSScopeProperty *sprop;
01810     JSString *str, *arg;
01811     void *mark;
01812     JSTokenStream *ts;
01813     JSPrincipals *principals;
01814     jschar *collected_args, *cp;
01815     size_t arg_length, args_length, old_args_length;
01816     JSTokenType tt;
01817     JSBool ok;
01818 
01819     fp = cx->fp;
01820     if (!(fp->flags & JSFRAME_CONSTRUCTING)) {
01821         obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
01822         if (!obj)
01823             return JS_FALSE;
01824         *rval = OBJECT_TO_JSVAL(obj);
01825     }
01826     fun = (JSFunction *) JS_GetPrivate(cx, obj);
01827     if (fun)
01828         return JS_TRUE;
01829 
01830     /*
01831      * NB: (new Function) is not lexically closed by its caller, it's just an
01832      * anonymous function in the top-level scope that its constructor inhabits.
01833      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
01834      * and so would a call to f from another top-level's script or function.
01835      *
01836      * In older versions, before call objects, a new Function was adopted by
01837      * its running context's globalObject, which might be different from the
01838      * top-level reachable from scopeChain (in HTML frames, e.g.).
01839      */
01840     parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
01841 
01842     fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
01843                          cx->runtime->atomState.anonymousAtom);
01844 
01845     if (!fun)
01846         return JS_FALSE;
01847 
01848     /*
01849      * Function is static and not called directly by other functions in this
01850      * file, therefore it is callable only as a native function by js_Invoke.
01851      * Find the scripted caller, possibly skipping other native frames such as
01852      * are built for Function.prototype.call or .apply activations that invoke
01853      * Function indirectly from a script.
01854      */
01855     JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
01856     caller = JS_GetScriptedCaller(cx, fp);
01857     if (caller) {
01858         principals = JS_EvalFramePrincipals(cx, fp, caller);
01859         filename = js_ComputeFilename(cx, caller, principals, &lineno);
01860     } else {
01861         filename = NULL;
01862         lineno = 0;
01863         principals = NULL;
01864     }
01865 
01866     /* Belt-and-braces: check that the caller has access to parent. */
01867     if (!js_CheckPrincipalsAccess(cx, parent, principals,
01868                                   CLASS_ATOM(cx, Function))) {
01869         return JS_FALSE;
01870     }
01871 
01872     n = argc ? argc - 1 : 0;
01873     if (n > 0) {
01874         /*
01875          * Collect the function-argument arguments into one string, separated
01876          * by commas, then make a tokenstream from that string, and scan it to
01877          * get the arguments.  We need to throw the full scanner at the
01878          * problem, because the argument string can legitimately contain
01879          * comments and linefeeds.  XXX It might be better to concatenate
01880          * everything up into a function definition and pass it to the
01881          * compiler, but doing it this way is less of a delta from the old
01882          * code.  See ECMA 15.3.2.1.
01883          */
01884         args_length = 0;
01885         for (i = 0; i < n; i++) {
01886             /* Collect the lengths for all the function-argument arguments. */
01887             arg = js_ValueToString(cx, argv[i]);
01888             if (!arg)
01889                 return JS_FALSE;
01890             argv[i] = STRING_TO_JSVAL(arg);
01891 
01892             /*
01893              * Check for overflow.  The < test works because the maximum
01894              * JSString length fits in 2 fewer bits than size_t has.
01895              */
01896             old_args_length = args_length;
01897             args_length = old_args_length + JSSTRING_LENGTH(arg);
01898             if (args_length < old_args_length) {
01899                 JS_ReportOutOfMemory(cx);
01900                 return JS_FALSE;
01901             }
01902         }
01903 
01904         /* Add 1 for each joining comma and check for overflow (two ways). */
01905         old_args_length = args_length;
01906         args_length = old_args_length + n - 1;
01907         if (args_length < old_args_length ||
01908             args_length >= ~(size_t)0 / sizeof(jschar)) {
01909             JS_ReportOutOfMemory(cx);
01910             return JS_FALSE;
01911         }
01912 
01913         /*
01914          * Allocate a string to hold the concatenated arguments, including room
01915          * for a terminating 0.  Mark cx->tempPool for later release, to free
01916          * collected_args and its tokenstream in one swoop.
01917          */
01918         mark = JS_ARENA_MARK(&cx->tempPool);
01919         JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
01920                                (args_length+1) * sizeof(jschar));
01921         if (!cp) {
01922             JS_ReportOutOfMemory(cx);
01923             return JS_FALSE;
01924         }
01925         collected_args = cp;
01926 
01927         /*
01928          * Concatenate the arguments into the new string, separated by commas.
01929          */
01930         for (i = 0; i < n; i++) {
01931             arg = JSVAL_TO_STRING(argv[i]);
01932             arg_length = JSSTRING_LENGTH(arg);
01933             (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
01934             cp += arg_length;
01935 
01936             /* Add separating comma or terminating 0. */
01937             *cp++ = (i + 1 < n) ? ',' : 0;
01938         }
01939 
01940         /*
01941          * Make a tokenstream (allocated from cx->tempPool) that reads from
01942          * the given string.
01943          */
01944         ts = js_NewTokenStream(cx, collected_args, args_length, filename,
01945                                lineno, principals);
01946         if (!ts) {
01947             JS_ARENA_RELEASE(&cx->tempPool, mark);
01948             return JS_FALSE;
01949         }
01950 
01951         /* The argument string may be empty or contain no tokens. */
01952         tt = js_GetToken(cx, ts);
01953         if (tt != TOK_EOF) {
01954             for (;;) {
01955                 /*
01956                  * Check that it's a name.  This also implicitly guards against
01957                  * TOK_ERROR, which was already reported.
01958                  */
01959                 if (tt != TOK_NAME)
01960                     goto bad_formal;
01961 
01962                 /*
01963                  * Get the atom corresponding to the name from the tokenstream;
01964                  * we're assured at this point that it's a valid identifier.
01965                  */
01966                 atom = CURRENT_TOKEN(ts).t_atom;
01967                 if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
01968                                              &obj2, &prop)) {
01969                     goto bad_formal;
01970                 }
01971                 sprop = (JSScopeProperty *) prop;
01972                 dupflag = 0;
01973                 if (sprop) {
01974                     ok = JS_TRUE;
01975                     if (obj2 == obj) {
01976                         const char *name = js_AtomToPrintableString(cx, atom);
01977 
01978                         /*
01979                          * A duplicate parameter name. We force a duplicate
01980                          * node on the SCOPE_LAST_PROP(scope) list with the
01981                          * same id, distinguished by the SPROP_IS_DUPLICATE
01982                          * flag, and not mapped by an entry in scope.
01983                          */
01984                         JS_ASSERT(sprop->getter == js_GetArgument);
01985                         ok = name &&
01986                              js_ReportCompileErrorNumber(cx, ts,
01987                                                          JSREPORT_TS |
01988                                                          JSREPORT_WARNING |
01989                                                          JSREPORT_STRICT,
01990                                                          JSMSG_DUPLICATE_FORMAL,
01991                                                          name);
01992 
01993                         dupflag = SPROP_IS_DUPLICATE;
01994                     }
01995                     OBJ_DROP_PROPERTY(cx, obj2, prop);
01996                     if (!ok)
01997                         goto bad_formal;
01998                     sprop = NULL;
01999                 }
02000                 if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
02001                                           js_GetArgument, js_SetArgument,
02002                                           SPROP_INVALID_SLOT,
02003                                           JSPROP_PERMANENT | JSPROP_SHARED,
02004                                           dupflag | SPROP_HAS_SHORTID,
02005                                           fun->nargs)) {
02006                     goto bad_formal;
02007                 }
02008                 if (fun->nargs == JS_BITMASK(16)) {
02009                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
02010                                          JSMSG_TOO_MANY_FUN_ARGS);
02011                     goto bad;
02012                 }
02013                 fun->nargs++;
02014 
02015                 /*
02016                  * Get the next token.  Stop on end of stream.  Otherwise
02017                  * insist on a comma, get another name, and iterate.
02018                  */
02019                 tt = js_GetToken(cx, ts);
02020                 if (tt == TOK_EOF)
02021                     break;
02022                 if (tt != TOK_COMMA)
02023                     goto bad_formal;
02024                 tt = js_GetToken(cx, ts);
02025             }
02026         }
02027 
02028         /* Clean up. */
02029         ok = js_CloseTokenStream(cx, ts);
02030         JS_ARENA_RELEASE(&cx->tempPool, mark);
02031         if (!ok)
02032             return JS_FALSE;
02033     }
02034 
02035     if (argc) {
02036         str = js_ValueToString(cx, argv[argc-1]);
02037     } else {
02038         /* Can't use cx->runtime->emptyString because we're called too early. */
02039         str = js_NewStringCopyZ(cx, js_empty_ucstr, 0);
02040     }
02041     if (!str)
02042         return JS_FALSE;
02043     if (argv) {
02044         /* Use the last arg (or this if argc == 0) as a local GC root. */
02045         argv[(intN)(argc-1)] = STRING_TO_JSVAL(str);
02046     }
02047 
02048     mark = JS_ARENA_MARK(&cx->tempPool);
02049     ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
02050                            filename, lineno, principals);
02051     if (!ts) {
02052         ok = JS_FALSE;
02053     } else {
02054         ok = js_CompileFunctionBody(cx, ts, fun) &&
02055              js_CloseTokenStream(cx, ts);
02056     }
02057     JS_ARENA_RELEASE(&cx->tempPool, mark);
02058     return ok;
02059 
02060 bad_formal:
02061     /*
02062      * Report "malformed formal parameter" iff no illegal char or similar
02063      * scanner error was already reported.
02064      */
02065     if (!(ts->flags & TSF_ERROR))
02066         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
02067 
02068 bad:
02069     /*
02070      * Clean up the arguments string and tokenstream if we failed to parse
02071      * the arguments.
02072      */
02073     (void)js_CloseTokenStream(cx, ts);
02074     JS_ARENA_RELEASE(&cx->tempPool, mark);
02075     return JS_FALSE;
02076 }
02077 
02078 JSObject *
02079 js_InitFunctionClass(JSContext *cx, JSObject *obj)
02080 {
02081     JSObject *proto;
02082     JSFunction *fun;
02083 
02084     proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
02085                          function_props, function_methods, NULL, NULL);
02086     if (!proto)
02087         return NULL;
02088     fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
02089     if (!fun)
02090         goto bad;
02091     fun->u.i.script = js_NewScript(cx, 1, 0, 0);
02092     if (!fun->u.i.script)
02093         goto bad;
02094     fun->u.i.script->code[0] = JSOP_STOP;
02095     fun->flags |= JSFUN_INTERPRETED;
02096     return proto;
02097 
02098 bad:
02099     cx->weakRoots.newborn[GCX_OBJECT] = NULL;
02100     return NULL;
02101 }
02102 
02103 JSObject *
02104 js_InitCallClass(JSContext *cx, JSObject *obj)
02105 {
02106     JSObject *proto;
02107 
02108     proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
02109                          call_props, NULL, NULL, NULL);
02110     if (!proto)
02111         return NULL;
02112 
02113     /*
02114      * Null Call.prototype's proto slot so that Object.prototype.* does not
02115      * pollute the scope of heavyweight functions.
02116      */
02117     OBJ_SET_PROTO(cx, proto, NULL);
02118     return proto;
02119 }
02120 
02121 JSFunction *
02122 js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
02123                uintN flags, JSObject *parent, JSAtom *atom)
02124 {
02125     JSFunction *fun;
02126     JSTempValueRooter tvr;
02127 
02128     /* If funobj is null, allocate an object for it. */
02129     if (funobj) {
02130         OBJ_SET_PARENT(cx, funobj, parent);
02131     } else {
02132         funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
02133         if (!funobj)
02134             return NULL;
02135     }
02136 
02137     /* Protect fun from any potential GC callback. */
02138     JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(funobj), &tvr);
02139 
02140     /*
02141      * Allocate fun after allocating funobj so slot allocation in js_NewObject
02142      * does not wipe out fun from newborn[GCX_PRIVATE].
02143      */
02144     fun = (JSFunction *) js_NewGCThing(cx, GCX_PRIVATE, sizeof(JSFunction));
02145     if (!fun)
02146         goto out;
02147 
02148     /* Initialize all function members. */
02149     fun->object = NULL;
02150     fun->nargs = nargs;
02151     fun->flags = flags & JSFUN_FLAGS_MASK;
02152     fun->u.n.native = native;
02153     fun->u.n.extra = 0;
02154     fun->u.n.spare = 0;
02155     fun->atom = atom;
02156     fun->clasp = NULL;
02157 
02158     /* Link fun to funobj and vice versa. */
02159     if (!js_LinkFunctionObject(cx, fun, funobj)) {
02160         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
02161         fun = NULL;
02162     }
02163 
02164 out:
02165     JS_POP_TEMP_ROOT(cx, &tvr);
02166     return fun;
02167 }
02168 
02169 JSObject *
02170 js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
02171 {
02172     JSObject *newfunobj;
02173     JSFunction *fun;
02174 
02175     JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
02176     newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
02177     if (!newfunobj)
02178         return NULL;
02179     fun = (JSFunction *) JS_GetPrivate(cx, funobj);
02180     if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
02181         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
02182         return NULL;
02183     }
02184     return newfunobj;
02185 }
02186 
02187 JSBool
02188 js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
02189 {
02190     if (!fun->object)
02191         fun->object = funobj;
02192     return JS_SetPrivate(cx, funobj, fun);
02193 }
02194 
02195 JSFunction *
02196 js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
02197                   uintN nargs, uintN attrs)
02198 {
02199     JSFunction *fun;
02200 
02201     fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
02202     if (!fun)
02203         return NULL;
02204     if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
02205                              OBJECT_TO_JSVAL(fun->object),
02206                              NULL, NULL,
02207                              attrs & ~JSFUN_FLAGS_MASK, NULL)) {
02208         return NULL;
02209     }
02210     return fun;
02211 }
02212 
02213 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
02214 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
02215 #endif
02216 
02217 JSFunction *
02218 js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
02219 {
02220     jsval v;
02221     JSObject *obj;
02222 
02223     v = *vp;
02224     obj = NULL;
02225     if (JSVAL_IS_OBJECT(v)) {
02226         obj = JSVAL_TO_OBJECT(v);
02227         if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
02228             if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
02229                 return NULL;
02230             obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
02231         }
02232     }
02233     if (!obj) {
02234         js_ReportIsNotFunction(cx, vp, flags);
02235         return NULL;
02236     }
02237     return (JSFunction *) JS_GetPrivate(cx, obj);
02238 }
02239 
02240 JSObject *
02241 js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags)
02242 {
02243     JSFunction *fun;
02244     JSObject *funobj;
02245     JSStackFrame *caller;
02246     JSPrincipals *principals;
02247 
02248     if (VALUE_IS_FUNCTION(cx, *vp))
02249         return JSVAL_TO_OBJECT(*vp);
02250 
02251     fun = js_ValueToFunction(cx, vp, flags);
02252     if (!fun)
02253         return NULL;
02254     funobj = fun->object;
02255     *vp = OBJECT_TO_JSVAL(funobj);
02256 
02257     caller = JS_GetScriptedCaller(cx, cx->fp);
02258     if (caller) {
02259         principals = JS_StackFramePrincipals(cx, caller);
02260     } else {
02261         /* No scripted caller, don't allow access. */
02262         principals = NULL;
02263     }
02264 
02265     if (!js_CheckPrincipalsAccess(cx, funobj, principals,
02266                                   fun->atom
02267                                   ? fun->atom
02268                                   : cx->runtime->atomState.anonymousAtom)) {
02269         return NULL;
02270     }
02271     return funobj;
02272 }
02273 
02274 JSObject *
02275 js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
02276 {
02277     JSObject *callable;
02278 
02279     callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp);
02280     if (callable &&
02281         ((callable->map->ops == &js_ObjectOps)
02282          ? OBJ_GET_CLASS(cx, callable)->call
02283          : callable->map->ops->call)) {
02284         *vp = OBJECT_TO_JSVAL(callable);
02285     } else {
02286         callable = js_ValueToFunctionObject(cx, vp, flags);
02287     }
02288     return callable;
02289 }
02290 
02291 void
02292 js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
02293 {
02294     JSStackFrame *fp;
02295     JSString *str;
02296     JSTempValueRooter tvr;
02297     const char *bytes, *source;
02298 
02299     for (fp = cx->fp; fp && !fp->spbase; fp = fp->down)
02300         continue;
02301     str = js_DecompileValueGenerator(cx,
02302                                      (fp && fp->spbase <= vp && vp < fp->sp)
02303                                      ? vp - fp->sp
02304                                      : (flags & JSV2F_SEARCH_STACK)
02305                                      ? JSDVG_SEARCH_STACK
02306                                      : JSDVG_IGNORE_STACK,
02307                                      *vp,
02308                                      NULL);
02309     if (str) {
02310         JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
02311         bytes = JS_GetStringBytes(str);
02312         if (flags & JSV2F_ITERATOR) {
02313             source = js_ValueToPrintableSource(cx, *vp);
02314             if (source) {
02315                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
02316                                      JSMSG_BAD_ITERATOR,
02317                                      bytes, js_iterator_str, source);
02318             }
02319         } else {
02320             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
02321                                  (uintN)((flags & JSV2F_CONSTRUCT)
02322                                          ? JSMSG_NOT_CONSTRUCTOR
02323                                          : JSMSG_NOT_FUNCTION),
02324                                  bytes);
02325         }
02326         JS_POP_TEMP_ROOT(cx, &tvr);
02327     }
02328 }