~ubuntu-branches/ubuntu/intrepid/xulrunner-1.9/intrepid

« back to all changes in this revision

Viewing changes to mozilla/js/src/jsfun.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack, Alexander Sack, Fabien Tassin
  • Date: 2008-02-13 11:47:21 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080213114721-7om0mgzngvuk9czv
Tags: 1.9~b3+nobinonly-0ubuntu1
* release FIREFOX_3_0b3_RELEASE

[ Alexander Sack ]
* submit patch that ships xpcshell to bugzilla
  - rename debian/patches/ship_xpcshell.patch =>
           debian/patches/bz410617_att295212_ship_xpcshell.patch
  - update debian/patches/series
* fix tooltip in epiphany: previously displayed out of screen bounds
  (LP: #37507)
  - add debian/patches/bz233371_att297343_fix_outofscreen_embed_tooltip.patch
  - update debian/patches/series
* use default upstream gcc tweaks for improved performance - especially of the
  javascript engine
  - update debian/rules
* update global extension/plugin patch to apply cleanly against latest code
  - update debian/patches/bzXXX_gre_extension_plugin_support.patch
* fix pyxpcom build failure introduced by recent commit
  - add debian/patches/bzXXX_fix_pyxpcom_build_failure.patch
  - update debian/patches/series
* add distro independent global install locations for extensions,
  /usr/lib/mozilla/extensions and /usr/share/mozilla/extensions
  - update debian/xulrunner-1.9.dirs
* support embedded tarball layout when either there is a *.tar.bz2 in orig tarball
  or if DEBIAN_MOZCLIENT_EMBEDDED is not unset (you will need this to produce embedded
  tarballs during |get-orig-source|
  - update debian/rules
* bump minimum libnss3-dev build requirements to >= 3.12.0~1.9b3
  - update debian/control
* bump minimum libnspr4-dev build requirements to >= 4.7.0~1.9b3
  - update debian/control

[ Fabien Tassin ]
* Drop patches applied upstream
  - drop debian/patches/bz410617_att295212_ship_xpcshell.patch
  - drop debian/patches/bz404634_att294921.patch
  - drop debian/patches/bz386610_python2.5_ftbfs_amd64.patch
  - drop debian/patches/bz373918_att295042.patch
  - drop debian/patches/bz408062_unstable_pc.patch
  - drop debian/patches/bz384304_fix_recursive_symlinks.patch
  - update debian/patches/series
* Refresh diverged patches:
  - update debian/patches/bzXXX_pc_honour_system_nspr_nss.patch
  - update debian/patches/rename_venkman_addon.patch
  - update debian/patches/bz344818_cairo_xrender.patch
* Install links for all .so libs in the -dev package
  - update debian/patches/dont_install_so_in_dev.patch
* Bump gtk requirement to 2.12 as per Mozilla bug 412432
  - update debian/control
* Add #DEBHELPER# token to postinst/prerm scripts
  - update debian/xulrunner-1.9.{postinst,prerm}
* Install previously missed libdbusservice.so
  - update debian/xulrunner-1.9.install
* Update venkman patch to also rename locales
  - update debian/patches/rename_venkman_addon.patch
* Bump requirement for system cairo to >= 1.5.8 as we now need
  the newly added cairo_path_extents()
  - update debian/rules
* Include mozilla-devscripts file using -include so ifneq could be omitted
  - update debian/rules
* Fix missing .so symlinks regression
  - update debian/patches/dont_install_so_in_dev.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 * JS function support.
43
 
 */
44
 
#include "jsstddef.h"
45
 
#include <string.h>
46
 
#include "jstypes.h"
47
 
#include "jsbit.h"
48
 
#include "jsutil.h" /* Added by JSIFY */
49
 
#include "jsapi.h"
50
 
#include "jsarray.h"
51
 
#include "jsatom.h"
52
 
#include "jscntxt.h"
53
 
#include "jsconfig.h"
54
 
#include "jsdbgapi.h"
55
 
#include "jsfun.h"
56
 
#include "jsgc.h"
57
 
#include "jsinterp.h"
58
 
#include "jslock.h"
59
 
#include "jsnum.h"
60
 
#include "jsobj.h"
61
 
#include "jsopcode.h"
62
 
#include "jsparse.h"
63
 
#include "jsscan.h"
64
 
#include "jsscope.h"
65
 
#include "jsscript.h"
66
 
#include "jsstr.h"
67
 
#include "jsexn.h"
68
 
 
69
 
#if JS_HAS_GENERATORS
70
 
# include "jsiter.h"
71
 
#endif
72
 
 
73
 
/* Generic function/call/arguments tinyids -- also reflected bit numbers. */
74
 
enum {
75
 
    CALL_ARGUMENTS  = -1,       /* predefined arguments local variable */
76
 
    ARGS_LENGTH     = -2,       /* number of actual args, arity if inactive */
77
 
    ARGS_CALLEE     = -3,       /* reference from arguments to active funobj */
78
 
    FUN_ARITY       = -4,       /* number of formal parameters; desired argc */
79
 
    FUN_NAME        = -5,       /* function name, "" if anonymous */
80
 
    FUN_CALLER      = -6        /* Function.prototype.caller, backward compat */
81
 
};
82
 
 
83
 
#if JSFRAME_OVERRIDE_BITS < 8
84
 
# error "not enough override bits in JSStackFrame.flags!"
85
 
#endif
86
 
 
87
 
#define TEST_OVERRIDE_BIT(fp, tinyid) \
88
 
    ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
89
 
 
90
 
#define SET_OVERRIDE_BIT(fp, tinyid) \
91
 
    ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
92
 
 
93
 
JSBool
94
 
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
95
 
{
96
 
    JSObject *argsobj;
97
 
 
98
 
    if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
99
 
        JS_ASSERT(fp->callobj);
100
 
        return OBJ_GET_PROPERTY(cx, fp->callobj,
101
 
                                ATOM_TO_JSID(cx->runtime->atomState
102
 
                                             .argumentsAtom),
103
 
                                vp);
104
 
    }
105
 
    argsobj = js_GetArgsObject(cx, fp);
106
 
    if (!argsobj)
107
 
        return JS_FALSE;
108
 
    *vp = OBJECT_TO_JSVAL(argsobj);
109
 
    return JS_TRUE;
110
 
}
111
 
 
112
 
static JSBool
113
 
MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
114
 
{
115
 
    JSObject *argsobj;
116
 
    jsval bmapval, bmapint;
117
 
    size_t nbits, nbytes;
118
 
    jsbitmap *bitmap;
119
 
 
120
 
    argsobj = fp->argsobj;
121
 
    (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
122
 
    nbits = fp->argc;
123
 
    JS_ASSERT(slot < nbits);
124
 
    if (JSVAL_IS_VOID(bmapval)) {
125
 
        if (nbits <= JSVAL_INT_BITS) {
126
 
            bmapint = 0;
127
 
            bitmap = (jsbitmap *) &bmapint;
128
 
        } else {
129
 
            nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap);
130
 
            bitmap = (jsbitmap *) JS_malloc(cx, nbytes);
131
 
            if (!bitmap)
132
 
                return JS_FALSE;
133
 
            memset(bitmap, 0, nbytes);
134
 
            bmapval = PRIVATE_TO_JSVAL(bitmap);
135
 
            JS_SetReservedSlot(cx, argsobj, 0, bmapval);
136
 
        }
137
 
    } else {
138
 
        if (nbits <= JSVAL_INT_BITS) {
139
 
            bmapint = JSVAL_TO_INT(bmapval);
140
 
            bitmap = (jsbitmap *) &bmapint;
141
 
        } else {
142
 
            bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
143
 
        }
144
 
    }
145
 
    JS_SET_BIT(bitmap, slot);
146
 
    if (bitmap == (jsbitmap *) &bmapint) {
147
 
        bmapval = INT_TO_JSVAL(bmapint);
148
 
        JS_SetReservedSlot(cx, argsobj, 0, bmapval);
149
 
    }
150
 
    return JS_TRUE;
151
 
}
152
 
 
153
 
/* NB: Infallible predicate, false does not mean error/exception. */
154
 
static JSBool
155
 
ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
156
 
{
157
 
    JSObject *argsobj;
158
 
    jsval bmapval, bmapint;
159
 
    jsbitmap *bitmap;
160
 
 
161
 
    argsobj = fp->argsobj;
162
 
    (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
163
 
    if (JSVAL_IS_VOID(bmapval))
164
 
        return JS_FALSE;
165
 
    if (fp->argc <= JSVAL_INT_BITS) {
166
 
        bmapint = JSVAL_TO_INT(bmapval);
167
 
        bitmap = (jsbitmap *) &bmapint;
168
 
    } else {
169
 
        bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
170
 
    }
171
 
    return JS_TEST_BIT(bitmap, slot) != 0;
172
 
}
173
 
 
174
 
JSBool
175
 
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp)
176
 
{
177
 
    jsval val;
178
 
    JSObject *obj;
179
 
    uintN slot;
180
 
 
181
 
    if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
182
 
        JS_ASSERT(fp->callobj);
183
 
        if (!OBJ_GET_PROPERTY(cx, fp->callobj,
184
 
                              ATOM_TO_JSID(cx->runtime->atomState
185
 
                                           .argumentsAtom),
186
 
                              &val)) {
187
 
            return JS_FALSE;
188
 
        }
189
 
        if (JSVAL_IS_PRIMITIVE(val)) {
190
 
            obj = js_ValueToNonNullObject(cx, val);
191
 
            if (!obj)
192
 
                return JS_FALSE;
193
 
        } else {
194
 
            obj = JSVAL_TO_OBJECT(val);
195
 
        }
196
 
        return OBJ_GET_PROPERTY(cx, obj, id, vp);
197
 
    }
198
 
 
199
 
    *vp = JSVAL_VOID;
200
 
    if (JSID_IS_INT(id)) {
201
 
        slot = (uintN) JSID_TO_INT(id);
202
 
        if (slot < fp->argc) {
203
 
            if (fp->argsobj && ArgWasDeleted(cx, fp, slot))
204
 
                return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
205
 
            *vp = fp->argv[slot];
206
 
        } else {
207
 
            /*
208
 
             * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
209
 
             * storage between the formal parameter and arguments[k] for all
210
 
             * fp->argc <= k && k < fp->fun->nargs.  For example, in
211
 
             *
212
 
             *   function f(x) { x = 42; return arguments[0]; }
213
 
             *   f();
214
 
             *
215
 
             * the call to f should return undefined, not 42.  If fp->argsobj
216
 
             * is null at this point, as it would be in the example, return
217
 
             * undefined in *vp.
218
 
             */
219
 
            if (fp->argsobj)
220
 
                return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
221
 
        }
222
 
    } else {
223
 
        if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
224
 
            if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH))
225
 
                return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
226
 
            *vp = INT_TO_JSVAL((jsint) fp->argc);
227
 
        }
228
 
    }
229
 
    return JS_TRUE;
230
 
}
231
 
 
232
 
JSObject *
233
 
js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
234
 
{
235
 
    JSObject *argsobj, *global, *parent;
236
 
 
237
 
    /*
238
 
     * We must be in a function activation; the function must be lightweight
239
 
     * or else fp must have a variable object.
240
 
     */
241
 
    JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj));
242
 
 
243
 
    /* Skip eval and debugger frames. */
244
 
    while (fp->flags & JSFRAME_SPECIAL)
245
 
        fp = fp->down;
246
 
 
247
 
    /* Create an arguments object for fp only if it lacks one. */
248
 
    argsobj = fp->argsobj;
249
 
    if (argsobj)
250
 
        return argsobj;
251
 
 
252
 
    /* Link the new object to fp so it can get actual argument values. */
253
 
    argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
254
 
    if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
255
 
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;
256
 
        return NULL;
257
 
    }
258
 
 
259
 
    /*
260
 
     * Give arguments an intrinsic scope chain link to fp's global object.
261
 
     * Since the arguments object lacks a prototype because js_ArgumentsClass
262
 
     * is not initialized, js_NewObject won't assign a default parent to it.
263
 
     *
264
 
     * Therefore if arguments is used as the head of an eval scope chain (via
265
 
     * a direct or indirect call to eval(program, arguments)), any reference
266
 
     * to a standard class object in the program will fail to resolve due to
267
 
     * js_GetClassPrototype not being able to find a global object containing
268
 
     * the standard prototype by starting from arguments and following parent.
269
 
     */
270
 
    global = fp->scopeChain;
271
 
    while ((parent = OBJ_GET_PARENT(cx, global)) != NULL)
272
 
        global = parent;
273
 
    STOBJ_SET_PARENT(argsobj, global);
274
 
    fp->argsobj = argsobj;
275
 
    return argsobj;
276
 
}
277
 
 
278
 
static JSBool
279
 
args_enumerate(JSContext *cx, JSObject *obj);
280
 
 
281
 
JSBool
282
 
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
283
 
{
284
 
    JSObject *argsobj;
285
 
    jsval bmapval, rval;
286
 
    JSBool ok;
287
 
    JSRuntime *rt;
288
 
 
289
 
    /*
290
 
     * Reuse args_enumerate here to reflect fp's actual arguments as indexed
291
 
     * elements of argsobj.  Do this first, before clearing and freeing the
292
 
     * deleted argument slot bitmap, because args_enumerate depends on that.
293
 
     */
294
 
    argsobj = fp->argsobj;
295
 
    ok = args_enumerate(cx, argsobj);
296
 
 
297
 
    /*
298
 
     * Now clear the deleted argument number bitmap slot and free the bitmap,
299
 
     * if one was actually created due to 'delete arguments[0]' or similar.
300
 
     */
301
 
    (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
302
 
    if (!JSVAL_IS_VOID(bmapval)) {
303
 
        JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
304
 
        if (fp->argc > JSVAL_INT_BITS)
305
 
            JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
306
 
    }
307
 
 
308
 
    /*
309
 
     * Now get the prototype properties so we snapshot fp->fun and fp->argc
310
 
     * before fp goes away.
311
 
     */
312
 
    rt = cx->runtime;
313
 
    ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
314
 
                         &rval);
315
 
    ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
316
 
                         &rval);
317
 
    ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
318
 
                         &rval);
319
 
    ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
320
 
                         &rval);
321
 
 
322
 
    /*
323
 
     * Clear the private pointer to fp, which is about to go away (js_Invoke).
324
 
     * Do this last because the args_enumerate and js_GetProperty calls above
325
 
     * need to follow the private slot to find fp.
326
 
     */
327
 
    ok &= JS_SetPrivate(cx, argsobj, NULL);
328
 
    fp->argsobj = NULL;
329
 
    return ok;
330
 
}
331
 
 
332
 
static JSBool
333
 
args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
334
 
{
335
 
    jsint slot;
336
 
    JSStackFrame *fp;
337
 
 
338
 
    if (!JSVAL_IS_INT(id))
339
 
        return JS_TRUE;
340
 
    fp = (JSStackFrame *)
341
 
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
342
 
    if (!fp)
343
 
        return JS_TRUE;
344
 
    JS_ASSERT(fp->argsobj);
345
 
 
346
 
    slot = JSVAL_TO_INT(id);
347
 
    switch (slot) {
348
 
      case ARGS_CALLEE:
349
 
      case ARGS_LENGTH:
350
 
        SET_OVERRIDE_BIT(fp, slot);
351
 
        break;
352
 
 
353
 
      default:
354
 
        if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot))
355
 
            return JS_FALSE;
356
 
        break;
357
 
    }
358
 
    return JS_TRUE;
359
 
}
360
 
 
361
 
static JSBool
362
 
args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
363
 
{
364
 
    jsint slot;
365
 
    JSStackFrame *fp;
366
 
 
367
 
    if (!JSVAL_IS_INT(id))
368
 
        return JS_TRUE;
369
 
    fp = (JSStackFrame *)
370
 
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
371
 
    if (!fp)
372
 
        return JS_TRUE;
373
 
    JS_ASSERT(fp->argsobj);
374
 
 
375
 
    slot = JSVAL_TO_INT(id);
376
 
    switch (slot) {
377
 
      case ARGS_CALLEE:
378
 
        if (!TEST_OVERRIDE_BIT(fp, slot))
379
 
            *vp = OBJECT_TO_JSVAL(fp->callee);
380
 
        break;
381
 
 
382
 
      case ARGS_LENGTH:
383
 
        if (!TEST_OVERRIDE_BIT(fp, slot))
384
 
            *vp = INT_TO_JSVAL((jsint)fp->argc);
385
 
        break;
386
 
 
387
 
      default:
388
 
        if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot))
389
 
            *vp = fp->argv[slot];
390
 
        break;
391
 
    }
392
 
    return JS_TRUE;
393
 
}
394
 
 
395
 
static JSBool
396
 
args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
397
 
{
398
 
    JSStackFrame *fp;
399
 
    jsint slot;
400
 
 
401
 
    if (!JSVAL_IS_INT(id))
402
 
        return JS_TRUE;
403
 
    fp = (JSStackFrame *)
404
 
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
405
 
    if (!fp)
406
 
        return JS_TRUE;
407
 
    JS_ASSERT(fp->argsobj);
408
 
 
409
 
    slot = JSVAL_TO_INT(id);
410
 
    switch (slot) {
411
 
      case ARGS_CALLEE:
412
 
      case ARGS_LENGTH:
413
 
        SET_OVERRIDE_BIT(fp, slot);
414
 
        break;
415
 
 
416
 
      default:
417
 
        if (FUN_INTERPRETED(fp->fun) &&
418
 
            (uintN)slot < fp->argc &&
419
 
            !ArgWasDeleted(cx, fp, slot)) {
420
 
            fp->argv[slot] = *vp;
421
 
        }
422
 
        break;
423
 
    }
424
 
    return JS_TRUE;
425
 
}
426
 
 
427
 
static JSBool
428
 
args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
429
 
             JSObject **objp)
430
 
{
431
 
    JSStackFrame *fp;
432
 
    uintN slot;
433
 
    JSString *str;
434
 
    JSAtom *atom;
435
 
    intN tinyid;
436
 
    jsval value;
437
 
 
438
 
    *objp = NULL;
439
 
    fp = (JSStackFrame *)
440
 
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
441
 
    if (!fp)
442
 
        return JS_TRUE;
443
 
    JS_ASSERT(fp->argsobj);
444
 
 
445
 
    if (JSVAL_IS_INT(id)) {
446
 
        slot = JSVAL_TO_INT(id);
447
 
        if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) {
448
 
            /* XXX ECMA specs DontEnum, contrary to other array-like objects */
449
 
            if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id),
450
 
                                   fp->argv[slot],
451
 
                                   args_getProperty, args_setProperty,
452
 
                                   0, NULL)) {
453
 
                return JS_FALSE;
454
 
            }
455
 
            *objp = obj;
456
 
        }
457
 
    } else {
458
 
        str = JSVAL_TO_STRING(id);
459
 
        atom = cx->runtime->atomState.lengthAtom;
460
 
        if (str == ATOM_TO_STRING(atom)) {
461
 
            tinyid = ARGS_LENGTH;
462
 
            value = INT_TO_JSVAL(fp->argc);
463
 
        } else {
464
 
            atom = cx->runtime->atomState.calleeAtom;
465
 
            if (str == ATOM_TO_STRING(atom)) {
466
 
                tinyid = ARGS_CALLEE;
467
 
                value = OBJECT_TO_JSVAL(fp->callee);
468
 
            } else {
469
 
                atom = NULL;
470
 
 
471
 
                /* Quell GCC overwarnings. */
472
 
                tinyid = 0;
473
 
                value = JSVAL_NULL;
474
 
            }
475
 
        }
476
 
 
477
 
        if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
478
 
            if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
479
 
                                         args_getProperty, args_setProperty, 0,
480
 
                                         SPROP_HAS_SHORTID, tinyid, NULL)) {
481
 
                return JS_FALSE;
482
 
            }
483
 
            *objp = obj;
484
 
        }
485
 
    }
486
 
 
487
 
    return JS_TRUE;
488
 
}
489
 
 
490
 
static JSBool
491
 
args_enumerate(JSContext *cx, JSObject *obj)
492
 
{
493
 
    JSStackFrame *fp;
494
 
    JSObject *pobj;
495
 
    JSProperty *prop;
496
 
    uintN slot, argc;
497
 
 
498
 
    fp = (JSStackFrame *)
499
 
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
500
 
    if (!fp)
501
 
        return JS_TRUE;
502
 
    JS_ASSERT(fp->argsobj);
503
 
 
504
 
    /*
505
 
     * Trigger reflection with value snapshot in args_resolve using a series
506
 
     * of js_LookupProperty calls.  We handle length, callee, and the indexed
507
 
     * argument properties.  We know that args_resolve covers all these cases
508
 
     * and creates direct properties of obj, but that it may fail to resolve
509
 
     * length or callee if overridden.
510
 
     */
511
 
    if (!js_LookupProperty(cx, obj,
512
 
                           ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
513
 
                           &pobj, &prop)) {
514
 
        return JS_FALSE;
515
 
    }
516
 
    if (prop)
517
 
        OBJ_DROP_PROPERTY(cx, pobj, prop);
518
 
 
519
 
    if (!js_LookupProperty(cx, obj,
520
 
                           ATOM_TO_JSID(cx->runtime->atomState.calleeAtom),
521
 
                           &pobj, &prop)) {
522
 
        return JS_FALSE;
523
 
    }
524
 
    if (prop)
525
 
        OBJ_DROP_PROPERTY(cx, pobj, prop);
526
 
 
527
 
    argc = fp->argc;
528
 
    for (slot = 0; slot < argc; slot++) {
529
 
        if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop))
530
 
            return JS_FALSE;
531
 
        if (prop)
532
 
            OBJ_DROP_PROPERTY(cx, pobj, prop);
533
 
    }
534
 
    return JS_TRUE;
535
 
}
536
 
 
537
 
#if JS_HAS_GENERATORS
538
 
/*
539
 
 * If a generator-iterator's arguments or call object escapes, it needs to
540
 
 * mark its generator object.
541
 
 */
542
 
static void
543
 
args_or_call_trace(JSTracer *trc, JSObject *obj)
544
 
{
545
 
    JSStackFrame *fp;
546
 
 
547
 
    fp = (JSStackFrame *) JS_GetPrivate(trc->context, obj);
548
 
    if (fp && (fp->flags & JSFRAME_GENERATOR)) {
549
 
        JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj,
550
 
                              "FRAME_TO_GENERATOR(fp)->obj");
551
 
    }
552
 
}
553
 
#else
554
 
# define args_or_call_trace NULL
555
 
#endif
556
 
 
557
 
/*
558
 
 * The Arguments class is not initialized via JS_InitClass, and must not be,
559
 
 * because its name is "Object".  Per ECMA, that causes instances of it to
560
 
 * delegate to the object named by Object.prototype.  It also ensures that
561
 
 * arguments.toString() returns "[object Object]".
562
 
 *
563
 
 * The JSClass functions below collaborate to lazily reflect and synchronize
564
 
 * actual argument values, argument count, and callee function object stored
565
 
 * in a JSStackFrame with their corresponding property values in the frame's
566
 
 * arguments object.
567
 
 */
568
 
JSClass js_ArgumentsClass = {
569
 
    js_Object_str,
570
 
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
571
 
    JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
572
 
    JS_PropertyStub,    args_delProperty,
573
 
    args_getProperty,   args_setProperty,
574
 
    args_enumerate,     (JSResolveOp) args_resolve,
575
 
    JS_ConvertStub,     JS_FinalizeStub,
576
 
    NULL,               NULL,
577
 
    NULL,               NULL,
578
 
    NULL,               NULL,
579
 
    JS_CLASS_TRACE(args_or_call_trace), NULL
580
 
};
581
 
 
582
 
JSObject *
583
 
js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
584
 
{
585
 
    JSObject *callobj, *funobj;
586
 
 
587
 
    /* Create a call object for fp only if it lacks one. */
588
 
    JS_ASSERT(fp->fun);
589
 
    callobj = fp->callobj;
590
 
    if (callobj)
591
 
        return callobj;
592
 
    JS_ASSERT(fp->fun);
593
 
 
594
 
    /* The default call parent is its function's parent (static link). */
595
 
    if (!parent) {
596
 
        funobj = fp->callee;
597
 
        if (funobj)
598
 
            parent = OBJ_GET_PARENT(cx, funobj);
599
 
    }
600
 
 
601
 
    /* Create the call object and link it to its stack frame. */
602
 
    callobj = js_NewObject(cx, &js_CallClass, NULL, parent);
603
 
    if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
604
 
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;
605
 
        return NULL;
606
 
    }
607
 
    fp->callobj = callobj;
608
 
 
609
 
    /* Make callobj be the scope chain and the variables object. */
610
 
    JS_ASSERT(fp->scopeChain == parent);
611
 
    fp->scopeChain = callobj;
612
 
    fp->varobj = callobj;
613
 
    return callobj;
614
 
}
615
 
 
616
 
static JSBool
617
 
call_enumerate(JSContext *cx, JSObject *obj);
618
 
 
619
 
JSBool
620
 
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
621
 
{
622
 
    JSObject *callobj;
623
 
    JSBool ok;
624
 
    jsid argsid;
625
 
    jsval aval;
626
 
 
627
 
    /*
628
 
     * Reuse call_enumerate here to reflect all actual args and vars into the
629
 
     * call object from fp.
630
 
     */
631
 
    callobj = fp->callobj;
632
 
    if (!callobj)
633
 
        return JS_TRUE;
634
 
    ok = call_enumerate(cx, callobj);
635
 
 
636
 
    /*
637
 
     * Get the arguments object to snapshot fp's actual argument values.
638
 
     */
639
 
    if (fp->argsobj) {
640
 
        if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
641
 
            argsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
642
 
            aval = OBJECT_TO_JSVAL(fp->argsobj);
643
 
            ok &= js_SetProperty(cx, callobj, argsid, &aval);
644
 
        }
645
 
        ok &= js_PutArgsObject(cx, fp);
646
 
    }
647
 
 
648
 
    /*
649
 
     * Clear the private pointer to fp, which is about to go away (js_Invoke).
650
 
     * Do this last because the call_enumerate and js_GetProperty calls above
651
 
     * need to follow the private slot to find fp.
652
 
     */
653
 
    ok &= JS_SetPrivate(cx, callobj, NULL);
654
 
    fp->callobj = NULL;
655
 
    return ok;
656
 
}
657
 
 
658
 
static JSBool
659
 
call_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
660
 
{
661
 
    JSStackFrame *fp;
662
 
    jsint slot;
663
 
 
664
 
    if (!JSVAL_IS_INT(id))
665
 
        return JS_TRUE;
666
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
667
 
    if (!fp)
668
 
        return JS_TRUE;
669
 
    JS_ASSERT(fp->fun);
670
 
 
671
 
    slot = JSVAL_TO_INT(id);
672
 
    switch (slot) {
673
 
      case CALL_ARGUMENTS:
674
 
        if (!TEST_OVERRIDE_BIT(fp, slot)) {
675
 
            JSObject *argsobj = js_GetArgsObject(cx, fp);
676
 
            if (!argsobj)
677
 
                return JS_FALSE;
678
 
            *vp = OBJECT_TO_JSVAL(argsobj);
679
 
        }
680
 
        break;
681
 
 
682
 
      default:
683
 
        if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
684
 
            *vp = fp->argv[slot];
685
 
        break;
686
 
    }
687
 
    return JS_TRUE;
688
 
}
689
 
 
690
 
static JSBool
691
 
call_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
692
 
{
693
 
    JSStackFrame *fp;
694
 
    jsint slot;
695
 
 
696
 
    if (!JSVAL_IS_INT(id))
697
 
        return JS_TRUE;
698
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
699
 
    if (!fp)
700
 
        return JS_TRUE;
701
 
    JS_ASSERT(fp->fun);
702
 
 
703
 
    slot = JSVAL_TO_INT(id);
704
 
    switch (slot) {
705
 
      case CALL_ARGUMENTS:
706
 
        SET_OVERRIDE_BIT(fp, slot);
707
 
        break;
708
 
 
709
 
      default:
710
 
        if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
711
 
            fp->argv[slot] = *vp;
712
 
        break;
713
 
    }
714
 
    return JS_TRUE;
715
 
}
716
 
 
717
 
JSBool
718
 
js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
719
 
{
720
 
    JSStackFrame *fp;
721
 
 
722
 
    JS_ASSERT(JSVAL_IS_INT(id));
723
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
724
 
    if (fp) {
725
 
        JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
726
 
        *vp = fp->vars[JSVAL_TO_INT(id)];
727
 
    }
728
 
    return JS_TRUE;
729
 
}
730
 
 
731
 
JSBool
732
 
js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
733
 
{
734
 
    JSStackFrame *fp;
735
 
 
736
 
    JS_ASSERT(JSVAL_IS_INT(id));
737
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
738
 
    if (fp) {
739
 
        JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
740
 
        fp->vars[JSVAL_TO_INT(id)] = *vp;
741
 
    }
742
 
    return JS_TRUE;
743
 
}
744
 
 
745
 
static JSBool
746
 
call_enumerate(JSContext *cx, JSObject *obj)
747
 
{
748
 
    JSStackFrame *fp;
749
 
    JSFunction *fun;
750
 
    uintN n, i, slot;
751
 
    void *mark;
752
 
    JSAtom **names, *name;
753
 
    JSObject *pobj;
754
 
    JSProperty *prop;
755
 
    jsval v;
756
 
 
757
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
758
 
    if (!fp)
759
 
        return JS_TRUE;
760
 
    JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
761
 
 
762
 
    /*
763
 
     * Reflect actual args from fp->argv for formal parameters, and local vars
764
 
     * and functions in fp->vars for declared variables and nested-at-top-level
765
 
     * local functions.
766
 
     */
767
 
    fun = fp->fun;
768
 
    n = fun->nargs + fun->u.i.nvars;
769
 
    if (n == 0)
770
 
        return JS_TRUE;
771
 
 
772
 
    mark = JS_ARENA_MARK(&cx->tempPool);
773
 
    names = js_GetLocalNames(cx, fun, &cx->tempPool, NULL);
774
 
    if (!names)
775
 
        goto out;
776
 
 
777
 
    for (i = 0; i != n; ++i) {
778
 
        name = names[i];
779
 
        if (!name)
780
 
            continue;
781
 
 
782
 
        /*
783
 
         * Trigger reflection by looking up the name of the argument or
784
 
         * variable.
785
 
         */
786
 
        if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(name), &pobj, &prop)) {
787
 
            names = NULL;
788
 
            goto out;
789
 
        }
790
 
 
791
 
        /*
792
 
         * At this point the call object always has a property corresponding
793
 
         * to the local name because call_resolve creates the property using
794
 
         * JSPROP_PERMANENT.
795
 
         */
796
 
        JS_ASSERT(prop && pobj == obj);
797
 
        slot = ((JSScopeProperty *) prop)->slot;
798
 
        OBJ_DROP_PROPERTY(cx, pobj, prop);
799
 
 
800
 
        v = (i < fun->nargs) ? fp->argv[i] : fp->vars[i - fun->nargs];
801
 
        LOCKED_OBJ_SET_SLOT(obj, slot, v);
802
 
    }
803
 
 
804
 
  out:
805
 
    JS_ARENA_RELEASE(&cx->tempPool, mark);
806
 
    return names != NULL;
807
 
}
808
 
 
809
 
static JSBool
810
 
call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
811
 
             JSObject **objp)
812
 
{
813
 
    JSStackFrame *fp;
814
 
    JSString *str;
815
 
    JSAtom *atom;
816
 
    JSLocalKind localKind;
817
 
    JSPropertyOp getter, setter;
818
 
    uintN slot, attrs;
819
 
    jsval *vp;
820
 
 
821
 
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
822
 
    if (!fp)
823
 
        return JS_TRUE;
824
 
    JS_ASSERT(fp->fun);
825
 
    JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
826
 
 
827
 
    if (!JSVAL_IS_STRING(id))
828
 
        return JS_TRUE;
829
 
 
830
 
    str = JSVAL_TO_STRING(id);
831
 
    atom = js_AtomizeString(cx, str, 0);
832
 
    if (!atom)
833
 
        return JS_FALSE;
834
 
 
835
 
    localKind = js_LookupLocal(cx, fp->fun, atom, &slot);
836
 
    if (localKind != JSLOCAL_NONE) {
837
 
        if (localKind == JSLOCAL_ARG) {
838
 
            JS_ASSERT(slot < fp->fun->nargs);
839
 
            vp = fp->argv;
840
 
            getter = setter = NULL;
841
 
            attrs = JSPROP_PERMANENT;
842
 
        } else {
843
 
            JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
844
 
            JS_ASSERT(fp->fun->u.i.nvars == fp->nvars);
845
 
            JS_ASSERT(slot < fp->nvars);
846
 
            vp = fp->vars;
847
 
            getter = js_GetCallVariable;
848
 
            setter = js_SetCallVariable;
849
 
            attrs = (localKind == JSLOCAL_CONST)
850
 
                    ? JSPROP_PERMANENT | JSPROP_READONLY
851
 
                    : JSPROP_PERMANENT;
852
 
        }
853
 
        if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), vp[slot],
854
 
                                     getter, setter, attrs,
855
 
                                     SPROP_HAS_SHORTID, (int) slot, NULL)) {
856
 
            return JS_FALSE;
857
 
        }
858
 
        *objp = obj;
859
 
        return JS_TRUE;
860
 
    }
861
 
 
862
 
    /*
863
 
     * Resolve arguments so that we never store a particular Call object's
864
 
     * arguments object reference in a Call prototype's |arguments| slot.
865
 
     */
866
 
    atom = cx->runtime->atomState.argumentsAtom;
867
 
    if (id == ATOM_KEY(atom)) {
868
 
        if (!js_DefineNativeProperty(cx, obj,
869
 
                                     ATOM_TO_JSID(atom), JSVAL_VOID,
870
 
                                     NULL, NULL, JSPROP_PERMANENT,
871
 
                                     SPROP_HAS_SHORTID, CALL_ARGUMENTS,
872
 
                                     NULL)) {
873
 
            return JS_FALSE;
874
 
        }
875
 
        *objp = obj;
876
 
        return JS_TRUE;
877
 
    }
878
 
    return JS_TRUE;
879
 
}
880
 
 
881
 
static JSBool
882
 
call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
883
 
{
884
 
    JSStackFrame *fp;
885
 
 
886
 
    if (type == JSTYPE_FUNCTION) {
887
 
        fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
888
 
        if (fp) {
889
 
            JS_ASSERT(fp->fun);
890
 
            *vp = OBJECT_TO_JSVAL(fp->callee);
891
 
        }
892
 
    }
893
 
    return JS_TRUE;
894
 
}
895
 
 
896
 
JS_FRIEND_DATA(JSClass) js_CallClass = {
897
 
    js_Call_str,
898
 
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
899
 
    JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
900
 
    JS_PropertyStub,    JS_PropertyStub,
901
 
    call_getProperty,   call_setProperty,
902
 
    call_enumerate,     (JSResolveOp)call_resolve,
903
 
    call_convert,       JS_FinalizeStub,
904
 
    NULL,               NULL,
905
 
    NULL,               NULL,
906
 
    NULL,               NULL,
907
 
    JS_CLASS_TRACE(args_or_call_trace), NULL,
908
 
};
909
 
 
910
 
/*
911
 
 * ECMA-262 specifies that length is a property of function object instances,
912
 
 * but we can avoid that space cost by delegating to a prototype property that
913
 
 * is JSPROP_PERMANENT and JSPROP_SHARED.  Each fun_getProperty call computes
914
 
 * a fresh length value based on the arity of the individual function object's
915
 
 * private data.
916
 
 *
917
 
 * The extensions below other than length, i.e., the ones not in ECMA-262,
918
 
 * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
919
 
 * with ECMA we must allow a delegating object to override them. Therefore to
920
 
 * avoid entraining garbage in Function.prototype slots, they must be resolved
921
 
 * in non-prototype function objects, wherefore the lazy_function_props table
922
 
 * and fun_resolve's use of it.
923
 
 */
924
 
#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
925
 
 
926
 
static JSPropertySpec function_props[] = {
927
 
    {js_length_str,    ARGS_LENGTH,    LENGTH_PROP_ATTRS, 0,0},
928
 
    {0,0,0,0,0}
929
 
};
930
 
 
931
 
typedef struct LazyFunctionProp {
932
 
    uint16      atomOffset;
933
 
    int8        tinyid;
934
 
    uint8       attrs;
935
 
} LazyFunctionProp;
936
 
 
937
 
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
938
 
static LazyFunctionProp lazy_function_props[] = {
939
 
    {ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT},
940
 
    {ATOM_OFFSET(arity),     FUN_ARITY,      JSPROP_PERMANENT},
941
 
    {ATOM_OFFSET(caller),    FUN_CALLER,     JSPROP_PERMANENT},
942
 
    {ATOM_OFFSET(name),      FUN_NAME,       JSPROP_PERMANENT},
943
 
};
944
 
 
945
 
static JSBool
946
 
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
947
 
{
948
 
    jsint slot;
949
 
    JSFunction *fun;
950
 
    JSStackFrame *fp;
951
 
 
952
 
    if (!JSVAL_IS_INT(id))
953
 
        return JS_TRUE;
954
 
    slot = JSVAL_TO_INT(id);
955
 
 
956
 
    /*
957
 
     * Loop because getter and setter can be delegated from another class,
958
 
     * but loop only for ARGS_LENGTH because we must pretend that f.length
959
 
     * is in each function instance f, per ECMA-262, instead of only in the
960
 
     * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
961
 
     * to make it appear so).
962
 
     *
963
 
     * This code couples tightly to the attributes for the function_props[]
964
 
     * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper.
965
 
     *
966
 
     * It's important to allow delegating objects, even though they inherit
967
 
     * this getter (fun_getProperty), to override arguments, arity, caller,
968
 
     * and name.  If we didn't return early for slot != ARGS_LENGTH, we would
969
 
     * clobber *vp with the native property value, instead of letting script
970
 
     * override that value in delegating objects.
971
 
     *
972
 
     * Note how that clobbering is what simulates JSPROP_READONLY for all of
973
 
     * the non-standard properties when the directly addressed object (obj)
974
 
     * is a function object (i.e., when this loop does not iterate).
975
 
     */
976
 
    while (!(fun = (JSFunction *)
977
 
                   JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
978
 
        if (slot != ARGS_LENGTH)
979
 
            return JS_TRUE;
980
 
        obj = OBJ_GET_PROTO(cx, obj);
981
 
        if (!obj)
982
 
            return JS_TRUE;
983
 
    }
984
 
 
985
 
    /* Find fun's top-most activation record. */
986
 
    for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
987
 
         fp = fp->down) {
988
 
        continue;
989
 
    }
990
 
 
991
 
    switch (slot) {
992
 
      case CALL_ARGUMENTS:
993
 
        /* Warn if strict about f.arguments or equivalent unqualified uses. */
994
 
        if (!JS_ReportErrorFlagsAndNumber(cx,
995
 
                                          JSREPORT_WARNING | JSREPORT_STRICT,
996
 
                                          js_GetErrorMessage, NULL,
997
 
                                          JSMSG_DEPRECATED_USAGE,
998
 
                                          js_arguments_str)) {
999
 
            return JS_FALSE;
1000
 
        }
1001
 
        if (fp) {
1002
 
            if (!js_GetArgsValue(cx, fp, vp))
1003
 
                return JS_FALSE;
1004
 
        } else {
1005
 
            *vp = JSVAL_NULL;
1006
 
        }
1007
 
        break;
1008
 
 
1009
 
      case ARGS_LENGTH:
1010
 
      case FUN_ARITY:
1011
 
            *vp = INT_TO_JSVAL((jsint)fun->nargs);
1012
 
        break;
1013
 
 
1014
 
      case FUN_NAME:
1015
 
        *vp = fun->atom
1016
 
              ? ATOM_KEY(fun->atom)
1017
 
              : STRING_TO_JSVAL(cx->runtime->emptyString);
1018
 
        break;
1019
 
 
1020
 
      case FUN_CALLER:
1021
 
        if (fp && fp->down && fp->down->fun)
1022
 
            *vp = OBJECT_TO_JSVAL(fp->down->callee);
1023
 
        else
1024
 
            *vp = JSVAL_NULL;
1025
 
        if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
1026
 
            id = ATOM_KEY(cx->runtime->atomState.callerAtom);
1027
 
            if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
1028
 
                return JS_FALSE;
1029
 
        }
1030
 
        break;
1031
 
 
1032
 
      default:
1033
 
        /* XXX fun[0] and fun.arguments[0] are equivalent. */
1034
 
        if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
1035
 
            *vp = fp->argv[slot];
1036
 
        break;
1037
 
    }
1038
 
 
1039
 
    return JS_TRUE;
1040
 
}
1041
 
 
1042
 
static JSBool
1043
 
fun_enumerate(JSContext *cx, JSObject *obj)
1044
 
{
1045
 
    jsid prototypeId;
1046
 
    JSObject *pobj;
1047
 
    JSProperty *prop;
1048
 
 
1049
 
    prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1050
 
    if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop))
1051
 
        return JS_FALSE;
1052
 
    if (prop)
1053
 
        OBJ_DROP_PROPERTY(cx, pobj, prop);
1054
 
    return JS_TRUE;
1055
 
}
1056
 
 
1057
 
static JSBool
1058
 
fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
1059
 
            JSObject **objp)
1060
 
{
1061
 
    JSFunction *fun;
1062
 
    JSAtom *atom;
1063
 
    uintN i;
1064
 
 
1065
 
    if (!JSVAL_IS_STRING(id))
1066
 
        return JS_TRUE;
1067
 
 
1068
 
    fun = GET_FUNCTION_PRIVATE(cx, obj);
1069
 
    JS_ASSERT(fun->object);
1070
 
 
1071
 
    /*
1072
 
     * No need to reflect fun.prototype in 'fun.prototype = ... '.
1073
 
     *
1074
 
     * This is not just an optimization, because we must not resolve when
1075
 
     * defining hidden properties during compilation. The setup code for the
1076
 
     * prototype and the lazy properties below eventually calls the property
1077
 
     * hooks for the function object. That in turn calls fun_reserveSlots to
1078
 
     * get the number of the reserved slots which is just the number of
1079
 
     * regular expressions literals in the function. When compiling, that
1080
 
     * number is not yet ready so we must make sure that fun_resolve does
1081
 
     * nothing until the code for the function is generated.
1082
 
     */
1083
 
    if (flags & JSRESOLVE_ASSIGNING)
1084
 
        return JS_TRUE;
1085
 
 
1086
 
    /*
1087
 
     * Ok, check whether id is 'prototype' and bootstrap the function object's
1088
 
     * prototype property.
1089
 
     */
1090
 
    atom = cx->runtime->atomState.classPrototypeAtom;
1091
 
    if (id == ATOM_KEY(atom)) {
1092
 
        JSObject *proto;
1093
 
 
1094
 
        /*
1095
 
         * Beware of the wacky case of a user function named Object -- trying
1096
 
         * to find a prototype for that will recur back here _ad perniciem_.
1097
 
         */
1098
 
        if (fun->atom == CLASS_ATOM(cx, Object))
1099
 
            return JS_TRUE;
1100
 
 
1101
 
        /*
1102
 
         * Make the prototype object to have the same parent as the function
1103
 
         * object itself.
1104
 
         */
1105
 
        proto = js_NewObject(cx, &js_ObjectClass, NULL,
1106
 
                             OBJ_GET_PARENT(cx, obj));
1107
 
        if (!proto)
1108
 
            return JS_FALSE;
1109
 
 
1110
 
        /*
1111
 
         * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1112
 
         * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1113
 
         * native "system" constructors such as Object or Function.  So lazily
1114
 
         * set the former here in fun_resolve, but eagerly define the latter
1115
 
         * in JS_InitClass, with the right attributes.
1116
 
         */
1117
 
        if (!js_SetClassPrototype(cx, obj, proto,
1118
 
                                  JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
1119
 
            cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1120
 
            return JS_FALSE;
1121
 
        }
1122
 
        *objp = obj;
1123
 
        return JS_TRUE;
1124
 
    }
1125
 
 
1126
 
    for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
1127
 
        LazyFunctionProp *lfp = &lazy_function_props[i];
1128
 
 
1129
 
        atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
1130
 
        if (id == ATOM_KEY(atom)) {
1131
 
            if (!js_DefineNativeProperty(cx, obj,
1132
 
                                         ATOM_TO_JSID(atom), JSVAL_VOID,
1133
 
                                         NULL, NULL, lfp->attrs,
1134
 
                                         SPROP_HAS_SHORTID, lfp->tinyid,
1135
 
                                         NULL)) {
1136
 
                return JS_FALSE;
1137
 
            }
1138
 
            *objp = obj;
1139
 
            return JS_TRUE;
1140
 
        }
1141
 
    }
1142
 
 
1143
 
    return JS_TRUE;
1144
 
}
1145
 
 
1146
 
static JSBool
1147
 
fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1148
 
{
1149
 
    switch (type) {
1150
 
      case JSTYPE_FUNCTION:
1151
 
        *vp = OBJECT_TO_JSVAL(obj);
1152
 
        return JS_TRUE;
1153
 
      default:
1154
 
        return js_TryValueOf(cx, obj, type, vp);
1155
 
    }
1156
 
}
1157
 
 
1158
 
#if JS_HAS_XDR
1159
 
 
1160
 
#include "jsxdrapi.h"
1161
 
 
1162
 
/* XXX store parent and proto, if defined */
1163
 
static JSBool
1164
 
fun_xdrObject(JSXDRState *xdr, JSObject **objp)
1165
 
{
1166
 
    JSContext *cx;
1167
 
    JSFunction *fun;
1168
 
    uint32 nullAtom;            /* flag to indicate if fun->atom is NULL */
1169
 
    uintN nargs, nvars, n;
1170
 
    uint32 localsword;          /* word to xdr argument and variable counts */
1171
 
    uint32 flagsword;           /* originally only flags was JS_XDRUint8'd */
1172
 
    JSTempValueRooter tvr;
1173
 
    JSBool ok;
1174
 
 
1175
 
    cx = xdr->cx;
1176
 
    if (xdr->mode == JSXDR_ENCODE) {
1177
 
        fun = GET_FUNCTION_PRIVATE(cx, *objp);
1178
 
        if (!FUN_INTERPRETED(fun)) {
1179
 
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1180
 
                                 JSMSG_NOT_SCRIPTED_FUNCTION,
1181
 
                                 JS_GetFunctionName(fun));
1182
 
            return JS_FALSE;
1183
 
        }
1184
 
        nullAtom = !fun->atom;
1185
 
        nargs = fun->nargs;
1186
 
        nvars = fun->u.i.nvars;
1187
 
        localsword = (nargs << 16) | nvars;
1188
 
        flagsword = fun->flags;
1189
 
    } else {
1190
 
        fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1191
 
        if (!fun)
1192
 
            return JS_FALSE;
1193
 
        STOBJ_SET_PARENT(fun->object, NULL);
1194
 
        STOBJ_SET_PROTO(fun->object, NULL);
1195
 
#ifdef __GNUC__
1196
 
        nvars = nargs = 0;   /* quell GCC uninitialized warning */
1197
 
#endif
1198
 
    }
1199
 
 
1200
 
    /* From here on, control flow must flow through label out. */
1201
 
    JS_PUSH_TEMP_ROOT_OBJECT(cx, fun->object, &tvr);
1202
 
    ok = JS_TRUE;
1203
 
 
1204
 
    if (!JS_XDRUint32(xdr, &nullAtom))
1205
 
        goto bad;
1206
 
    if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))
1207
 
        goto bad;
1208
 
    if (!JS_XDRUint32(xdr, &localsword) ||
1209
 
        !JS_XDRUint32(xdr, &flagsword)) {
1210
 
        goto bad;
1211
 
    }
1212
 
 
1213
 
    if (xdr->mode == JSXDR_DECODE) {
1214
 
        nargs = localsword >> 16;
1215
 
        nvars = localsword & JS_BITMASK(16);
1216
 
        JS_ASSERT(flagsword | JSFUN_INTERPRETED);
1217
 
        fun->flags = (uint16) flagsword;
1218
 
    }
1219
 
 
1220
 
    /* do arguments and local vars */
1221
 
    if (fun->object && (n = nargs + nvars) != 0) {
1222
 
        void *mark;
1223
 
        uintN i;
1224
 
        uintN bitmapLength;
1225
 
        uint32 *bitmap;
1226
 
        JSAtom **names, *name;
1227
 
        JSLocalKind localKind;
1228
 
 
1229
 
        mark = JS_ARENA_MARK(&xdr->cx->tempPool);
1230
 
 
1231
 
        /* From this point the control must flow through label release_mark. */
1232
 
        bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
1233
 
        if (xdr->mode == JSXDR_ENCODE) {
1234
 
            names = js_GetLocalNames(xdr->cx, fun, &xdr->cx->tempPool, &bitmap);
1235
 
            if (!names) {
1236
 
                ok = JS_FALSE;
1237
 
                goto release_mark;
1238
 
            }
1239
 
        } else {
1240
 
#ifdef __GNUC__
1241
 
            names = NULL;   /* quell GCC uninitialized warning */
1242
 
#endif
1243
 
            JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
1244
 
                                   bitmapLength * sizeof *bitmap);
1245
 
            if (!bitmap) {
1246
 
                js_ReportOutOfScriptQuota(xdr->cx);
1247
 
                ok = JS_FALSE;
1248
 
                goto release_mark;
1249
 
            }
1250
 
        }
1251
 
        for (i = 0; i != bitmapLength; ++i) {
1252
 
            ok = JS_XDRUint32(xdr, &bitmap[i]);
1253
 
            if (!ok)
1254
 
                goto release_mark;
1255
 
        }
1256
 
        for (i = 0; i != n; ++i) {
1257
 
            if (i < nargs &&
1258
 
                !(bitmap[i / JS_BITS_PER_UINT32] &
1259
 
                  JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) {
1260
 
                if (xdr->mode == JSXDR_DECODE) {
1261
 
                    ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG);
1262
 
                    if (!ok)
1263
 
                        goto release_mark;
1264
 
                } else {
1265
 
                    JS_ASSERT(!names[i]);
1266
 
                }
1267
 
                continue;
1268
 
            }
1269
 
            if (xdr->mode == JSXDR_ENCODE)
1270
 
                name = names[i];
1271
 
            ok = js_XDRStringAtom(xdr, &name);
1272
 
            if (!ok)
1273
 
                goto release_mark;
1274
 
            if (xdr->mode == JSXDR_DECODE) {
1275
 
                localKind = (i < nargs)
1276
 
                            ? JSLOCAL_ARG
1277
 
                            : bitmap[i / JS_BITS_PER_UINT32] &
1278
 
                              JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
1279
 
                            ? JSLOCAL_CONST
1280
 
                            : JSLOCAL_VAR;
1281
 
                ok = js_AddLocal(xdr->cx, fun, name, localKind);
1282
 
                if (!ok)
1283
 
                    goto release_mark;
1284
 
            }
1285
 
        }
1286
 
        ok = JS_TRUE;
1287
 
 
1288
 
      release_mark:
1289
 
        JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
1290
 
        if (!ok)
1291
 
            goto out;
1292
 
 
1293
 
        if (xdr->mode == JSXDR_DECODE)
1294
 
            js_FreezeLocalNames(cx, fun);
1295
 
    }
1296
 
 
1297
 
    if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
1298
 
        goto bad;
1299
 
 
1300
 
    if (xdr->mode == JSXDR_DECODE) {
1301
 
        *objp = fun->object;
1302
 
        js_CallNewScriptHook(cx, fun->u.i.script, fun);
1303
 
    }
1304
 
 
1305
 
out:
1306
 
    JS_POP_TEMP_ROOT(cx, &tvr);
1307
 
    return ok;
1308
 
 
1309
 
bad:
1310
 
    ok = JS_FALSE;
1311
 
    goto out;
1312
 
}
1313
 
 
1314
 
#else  /* !JS_HAS_XDR */
1315
 
 
1316
 
#define fun_xdrObject NULL
1317
 
 
1318
 
#endif /* !JS_HAS_XDR */
1319
 
 
1320
 
/*
1321
 
 * [[HasInstance]] internal method for Function objects: fetch the .prototype
1322
 
 * property of its 'this' parameter, and walks the prototype chain of v (only
1323
 
 * if v is an object) returning true if .prototype is found.
1324
 
 */
1325
 
static JSBool
1326
 
fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
1327
 
{
1328
 
    jsval pval;
1329
 
 
1330
 
    if (!OBJ_GET_PROPERTY(cx, obj,
1331
 
                          ATOM_TO_JSID(cx->runtime->atomState
1332
 
                                       .classPrototypeAtom),
1333
 
                          &pval)) {
1334
 
        return JS_FALSE;
1335
 
    }
1336
 
 
1337
 
    if (JSVAL_IS_PRIMITIVE(pval)) {
1338
 
        /*
1339
 
         * Throw a runtime error if instanceof is called on a function that
1340
 
         * has a non-object as its .prototype value.
1341
 
         */
1342
 
        js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE,
1343
 
                            -1, OBJECT_TO_JSVAL(obj), NULL);
1344
 
        return JS_FALSE;
1345
 
    }
1346
 
 
1347
 
    return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
1348
 
}
1349
 
 
1350
 
static void
1351
 
fun_trace(JSTracer *trc, JSObject *obj)
1352
 
{
1353
 
    JSFunction *fun;
1354
 
 
1355
 
    /* A newborn function object may have a not yet initialized private slot. */
1356
 
    fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
1357
 
    if (fun)
1358
 
        JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private");
1359
 
}
1360
 
 
1361
 
static uint32
1362
 
fun_reserveSlots(JSContext *cx, JSObject *obj)
1363
 
{
1364
 
    JSFunction *fun;
1365
 
 
1366
 
    /*
1367
 
     * We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during
1368
 
     * js_InitFunctionClass invocation the function is called before the
1369
 
     * private slot of the function object is set.
1370
 
     */
1371
 
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
1372
 
    return (fun && FUN_INTERPRETED(fun) &&
1373
 
            fun->u.i.script && fun->u.i.script->regexpsOffset != 0)
1374
 
           ? JS_SCRIPT_REGEXPS(fun->u.i.script)->length
1375
 
           : 0;
1376
 
}
1377
 
 
1378
 
/*
1379
 
 * Reserve two slots in all function objects for XPConnect.  Note that this
1380
 
 * does not bloat every instance, only those on which reserved slots are set,
1381
 
 * and those on which ad-hoc properties are defined.
1382
 
 */
1383
 
JS_FRIEND_DATA(JSClass) js_FunctionClass = {
1384
 
    js_Function_str,
1385
 
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) |
1386
 
    JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
1387
 
    JS_PropertyStub,  JS_PropertyStub,
1388
 
    fun_getProperty,  JS_PropertyStub,
1389
 
    fun_enumerate,    (JSResolveOp)fun_resolve,
1390
 
    fun_convert,      JS_FinalizeStub,
1391
 
    NULL,             NULL,
1392
 
    NULL,             NULL,
1393
 
    fun_xdrObject,    fun_hasInstance,
1394
 
    JS_CLASS_TRACE(fun_trace), fun_reserveSlots
1395
 
};
1396
 
 
1397
 
static JSBool
1398
 
fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
1399
 
{
1400
 
    jsval fval;
1401
 
    JSObject *obj;
1402
 
    JSFunction *fun;
1403
 
    JSString *str;
1404
 
 
1405
 
    fval = vp[1];
1406
 
    if (!VALUE_IS_FUNCTION(cx, fval)) {
1407
 
        /*
1408
 
         * If we don't have a function to start off with, try converting the
1409
 
         * object to a function. If that doesn't work, complain.
1410
 
         */
1411
 
        if (!JSVAL_IS_PRIMITIVE(fval)) {
1412
 
            obj = JSVAL_TO_OBJECT(fval);
1413
 
            if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
1414
 
                                                 &fval)) {
1415
 
                return JS_FALSE;
1416
 
            }
1417
 
            vp[1] = fval;
1418
 
        }
1419
 
        if (!VALUE_IS_FUNCTION(cx, fval)) {
1420
 
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1421
 
                                 JSMSG_INCOMPATIBLE_PROTO,
1422
 
                                 js_Function_str, js_toString_str,
1423
 
                                 JS_GetTypeName(cx, JS_TypeOfValue(cx, fval)));
1424
 
            return JS_FALSE;
1425
 
        }
1426
 
    }
1427
 
 
1428
 
    obj = JSVAL_TO_OBJECT(fval);
1429
 
    if (argc != 0 && !js_ValueToECMAUint32(cx, vp[2], &indent))
1430
 
        return JS_FALSE;
1431
 
 
1432
 
    JS_ASSERT(JS_ObjectIsFunction(cx, obj));
1433
 
    fun = GET_FUNCTION_PRIVATE(cx, obj);
1434
 
    if (!fun)
1435
 
        return JS_TRUE;
1436
 
    str = JS_DecompileFunction(cx, fun, (uintN)indent);
1437
 
    if (!str)
1438
 
        return JS_FALSE;
1439
 
    *vp = STRING_TO_JSVAL(str);
1440
 
    return JS_TRUE;
1441
 
}
1442
 
 
1443
 
static JSBool
1444
 
fun_toString(JSContext *cx, uintN argc, jsval *vp)
1445
 
{
1446
 
    return fun_toStringHelper(cx, 0, argc,  vp);
1447
 
}
1448
 
 
1449
 
#if JS_HAS_TOSOURCE
1450
 
static JSBool
1451
 
fun_toSource(JSContext *cx, uintN argc, jsval *vp)
1452
 
{
1453
 
    return fun_toStringHelper(cx, JS_DONT_PRETTY_PRINT, argc, vp);
1454
 
}
1455
 
#endif
1456
 
 
1457
 
static const char call_str[] = "call";
1458
 
 
1459
 
static JSBool
1460
 
fun_call(JSContext *cx, uintN argc, jsval *vp)
1461
 
{
1462
 
    JSObject *obj;
1463
 
    jsval fval, *argv, *invokevp;
1464
 
    JSString *str;
1465
 
    void *mark;
1466
 
    JSBool ok;
1467
 
 
1468
 
    obj = JSVAL_TO_OBJECT(vp[1]);
1469
 
    if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
1470
 
        return JS_FALSE;
1471
 
    fval = vp[1];
1472
 
 
1473
 
    if (!VALUE_IS_FUNCTION(cx, fval)) {
1474
 
        str = JS_ValueToString(cx, fval);
1475
 
        if (str) {
1476
 
            const char *bytes = js_GetStringBytes(cx, str);
1477
 
 
1478
 
            if (bytes) {
1479
 
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1480
 
                                     JSMSG_INCOMPATIBLE_PROTO,
1481
 
                                     js_Function_str, call_str,
1482
 
                                     bytes);
1483
 
            }
1484
 
        }
1485
 
        return JS_FALSE;
1486
 
    }
1487
 
 
1488
 
    argv = vp + 2;
1489
 
    if (argc == 0) {
1490
 
        /* Call fun with its global object as the 'this' param if no args. */
1491
 
        obj = NULL;
1492
 
    } else {
1493
 
        /* Otherwise convert the first arg to 'this' and skip over it. */
1494
 
        if (!JSVAL_IS_PRIMITIVE(argv[0]))
1495
 
            obj = JSVAL_TO_OBJECT(argv[0]);
1496
 
        else if (!js_ValueToObject(cx, argv[0], &obj))
1497
 
            return JS_FALSE;
1498
 
        argc--;
1499
 
        argv++;
1500
 
    }
1501
 
 
1502
 
    /* Allocate stack space for fval, obj, and the args. */
1503
 
    invokevp = js_AllocStack(cx, 2 + argc, &mark);
1504
 
    if (!invokevp)
1505
 
        return JS_FALSE;
1506
 
 
1507
 
    /* Push fval, obj, and the args. */
1508
 
    invokevp[0] = fval;
1509
 
    invokevp[1] = OBJECT_TO_JSVAL(obj);
1510
 
    memcpy(invokevp + 2, argv, argc * sizeof *argv);
1511
 
 
1512
 
    ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
1513
 
    *vp = *invokevp;
1514
 
    js_FreeStack(cx, mark);
1515
 
    return ok;
1516
 
}
1517
 
 
1518
 
static JSBool
1519
 
fun_apply(JSContext *cx, uintN argc, jsval *vp)
1520
 
{
1521
 
    JSObject *obj, *aobj;
1522
 
    jsval fval, *invokevp, *sp;
1523
 
    JSString *str;
1524
 
    jsuint length;
1525
 
    JSBool arraylike, ok;
1526
 
    void *mark;
1527
 
    uintN i;
1528
 
 
1529
 
    if (argc == 0) {
1530
 
        /* Will get globalObject as 'this' and no other arguments. */
1531
 
        return fun_call(cx, argc, vp);
1532
 
    }
1533
 
 
1534
 
    obj = JSVAL_TO_OBJECT(vp[1]);
1535
 
    if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
1536
 
        return JS_FALSE;
1537
 
    fval = vp[1];
1538
 
 
1539
 
    if (!VALUE_IS_FUNCTION(cx, fval)) {
1540
 
        str = JS_ValueToString(cx, fval);
1541
 
        if (str) {
1542
 
            const char *bytes = js_GetStringBytes(cx, str);
1543
 
 
1544
 
            if (bytes) {
1545
 
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1546
 
                                     JSMSG_INCOMPATIBLE_PROTO,
1547
 
                                     js_Function_str, "apply",
1548
 
                                     bytes);
1549
 
            }
1550
 
        }
1551
 
        return JS_FALSE;
1552
 
    }
1553
 
 
1554
 
    /* Quell GCC overwarnings. */
1555
 
    aobj = NULL;
1556
 
    length = 0;
1557
 
 
1558
 
    if (argc >= 2) {
1559
 
        /* If the 2nd arg is null or void, call the function with 0 args. */
1560
 
        if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) {
1561
 
            argc = 0;
1562
 
        } else {
1563
 
            /* The second arg must be an array (or arguments object). */
1564
 
            arraylike = JS_FALSE;
1565
 
            if (!JSVAL_IS_PRIMITIVE(vp[3])) {
1566
 
                aobj = JSVAL_TO_OBJECT(vp[3]);
1567
 
                if (!js_IsArrayLike(cx, aobj, &arraylike, &length))
1568
 
                    return JS_FALSE;
1569
 
            }
1570
 
            if (!arraylike) {
1571
 
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1572
 
                                     JSMSG_BAD_APPLY_ARGS, "apply");
1573
 
                return JS_FALSE;
1574
 
            }
1575
 
        }
1576
 
    }
1577
 
 
1578
 
    /* Convert the first arg to 'this' and skip over it. */
1579
 
    if (!JSVAL_IS_PRIMITIVE(vp[2]))
1580
 
        obj = JSVAL_TO_OBJECT(vp[2]);
1581
 
    else if (!js_ValueToObject(cx, vp[2], &obj))
1582
 
        return JS_FALSE;
1583
 
 
1584
 
    /* Allocate stack space for fval, obj, and the args. */
1585
 
    argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
1586
 
    invokevp = js_AllocStack(cx, 2 + argc, &mark);
1587
 
    if (!invokevp)
1588
 
        return JS_FALSE;
1589
 
 
1590
 
    /* Push fval, obj, and aobj's elements as args. */
1591
 
    sp = invokevp;
1592
 
    *sp++ = fval;
1593
 
    *sp++ = OBJECT_TO_JSVAL(obj);
1594
 
    for (i = 0; i < argc; i++) {
1595
 
        ok = JS_GetElement(cx, aobj, (jsint)i, sp);
1596
 
        if (!ok)
1597
 
            goto out;
1598
 
        sp++;
1599
 
    }
1600
 
 
1601
 
    ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
1602
 
    *vp = *invokevp;
1603
 
out:
1604
 
    js_FreeStack(cx, mark);
1605
 
    return ok;
1606
 
}
1607
 
 
1608
 
#ifdef NARCISSUS
1609
 
static JSBool
1610
 
fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
1611
 
{
1612
 
    JSObject *aobj;
1613
 
    uintN length, i;
1614
 
    void *mark;
1615
 
    jsval *invokevp, *sp;
1616
 
    JSBool ok;
1617
 
 
1618
 
    if (JSVAL_IS_PRIMITIVE(vp[2]) ||
1619
 
        (aobj = JSVAL_TO_OBJECT(vp[2]),
1620
 
         OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass &&
1621
 
         OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) {
1622
 
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1623
 
                             JSMSG_BAD_APPLY_ARGS, "__applyConstruct__");
1624
 
        return JS_FALSE;
1625
 
    }
1626
 
 
1627
 
    if (!js_GetLengthProperty(cx, aobj, &length))
1628
 
        return JS_FALSE;
1629
 
 
1630
 
    if (length >= ARRAY_INIT_LIMIT)
1631
 
        length = ARRAY_INIT_LIMIT - 1;
1632
 
    invokevp = js_AllocStack(cx, 2 + length, &mark);
1633
 
    if (!invokevp)
1634
 
        return JS_FALSE;
1635
 
 
1636
 
    sp = invokevp;
1637
 
    *sp++ = vp[1];
1638
 
    *sp++ = JSVAL_NULL; /* This is filled automagically. */
1639
 
    for (i = 0; i < length; i++) {
1640
 
        ok = JS_GetElement(cx, aobj, (jsint)i, sp);
1641
 
        if (!ok)
1642
 
            goto out;
1643
 
        sp++;
1644
 
    }
1645
 
 
1646
 
    ok = js_InvokeConstructor(cx, invokevp, length);
1647
 
    *vp = *invokevp;
1648
 
out:
1649
 
    js_FreeStack(cx, mark);
1650
 
    return ok;
1651
 
}
1652
 
#endif
1653
 
 
1654
 
static JSFunctionSpec function_methods[] = {
1655
 
#if JS_HAS_TOSOURCE
1656
 
    JS_FN(js_toSource_str,   fun_toSource,   0,0,0),
1657
 
#endif
1658
 
    JS_FN(js_toString_str,   fun_toString,   0,0,0),
1659
 
    JS_FN("apply",           fun_apply,      0,2,0),
1660
 
    JS_FN(call_str,          fun_call,       0,1,0),
1661
 
#ifdef NARCISSUS
1662
 
    JS_FN("__applyConstructor__", fun_applyConstructor, 0,1,0),
1663
 
#endif
1664
 
    JS_FS_END
1665
 
};
1666
 
 
1667
 
static JSBool
1668
 
Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1669
 
{
1670
 
    JSStackFrame *fp, *caller;
1671
 
    JSFunction *fun;
1672
 
    JSObject *parent;
1673
 
    uintN i, n, lineno;
1674
 
    JSAtom *atom;
1675
 
    const char *filename;
1676
 
    JSBool ok;
1677
 
    JSString *str, *arg;
1678
 
    JSTokenStream ts;
1679
 
    JSPrincipals *principals;
1680
 
    jschar *collected_args, *cp;
1681
 
    void *mark;
1682
 
    size_t arg_length, args_length, old_args_length;
1683
 
    JSTokenType tt;
1684
 
 
1685
 
    fp = cx->fp;
1686
 
    if (!(fp->flags & JSFRAME_CONSTRUCTING)) {
1687
 
        obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
1688
 
        if (!obj)
1689
 
            return JS_FALSE;
1690
 
        *rval = OBJECT_TO_JSVAL(obj);
1691
 
    }
1692
 
 
1693
 
    /*
1694
 
     * The constructor is called before the private slot is initialized so we
1695
 
     * must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here.
1696
 
     */
1697
 
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
1698
 
    if (fun)
1699
 
        return JS_TRUE;
1700
 
 
1701
 
    /*
1702
 
     * NB: (new Function) is not lexically closed by its caller, it's just an
1703
 
     * anonymous function in the top-level scope that its constructor inhabits.
1704
 
     * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
1705
 
     * and so would a call to f from another top-level's script or function.
1706
 
     *
1707
 
     * In older versions, before call objects, a new Function was adopted by
1708
 
     * its running context's globalObject, which might be different from the
1709
 
     * top-level reachable from scopeChain (in HTML frames, e.g.).
1710
 
     */
1711
 
    parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
1712
 
 
1713
 
    fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
1714
 
                         parent, cx->runtime->atomState.anonymousAtom);
1715
 
 
1716
 
    if (!fun)
1717
 
        return JS_FALSE;
1718
 
 
1719
 
    /*
1720
 
     * Function is static and not called directly by other functions in this
1721
 
     * file, therefore it is callable only as a native function by js_Invoke.
1722
 
     * Find the scripted caller, possibly skipping other native frames such as
1723
 
     * are built for Function.prototype.call or .apply activations that invoke
1724
 
     * Function indirectly from a script.
1725
 
     */
1726
 
    JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
1727
 
    caller = JS_GetScriptedCaller(cx, fp);
1728
 
    if (caller) {
1729
 
        filename = caller->script->filename;
1730
 
        lineno = js_PCToLineNumber(cx, caller->script, caller->pc);
1731
 
        principals = JS_EvalFramePrincipals(cx, fp, caller);
1732
 
    } else {
1733
 
        filename = NULL;
1734
 
        lineno = 0;
1735
 
        principals = NULL;
1736
 
    }
1737
 
 
1738
 
    /* Belt-and-braces: check that the caller has access to parent. */
1739
 
    if (!js_CheckPrincipalsAccess(cx, parent, principals,
1740
 
                                  CLASS_ATOM(cx, Function))) {
1741
 
        return JS_FALSE;
1742
 
    }
1743
 
 
1744
 
    n = argc ? argc - 1 : 0;
1745
 
    if (n > 0) {
1746
 
        enum { OK, BAD, BAD_FORMAL } state;
1747
 
 
1748
 
        /*
1749
 
         * Collect the function-argument arguments into one string, separated
1750
 
         * by commas, then make a tokenstream from that string, and scan it to
1751
 
         * get the arguments.  We need to throw the full scanner at the
1752
 
         * problem, because the argument string can legitimately contain
1753
 
         * comments and linefeeds.  XXX It might be better to concatenate
1754
 
         * everything up into a function definition and pass it to the
1755
 
         * compiler, but doing it this way is less of a delta from the old
1756
 
         * code.  See ECMA 15.3.2.1.
1757
 
         */
1758
 
        state = BAD_FORMAL;
1759
 
        args_length = 0;
1760
 
        for (i = 0; i < n; i++) {
1761
 
            /* Collect the lengths for all the function-argument arguments. */
1762
 
            arg = js_ValueToString(cx, argv[i]);
1763
 
            if (!arg)
1764
 
                return JS_FALSE;
1765
 
            argv[i] = STRING_TO_JSVAL(arg);
1766
 
 
1767
 
            /*
1768
 
             * Check for overflow.  The < test works because the maximum
1769
 
             * JSString length fits in 2 fewer bits than size_t has.
1770
 
             */
1771
 
            old_args_length = args_length;
1772
 
            args_length = old_args_length + JSSTRING_LENGTH(arg);
1773
 
            if (args_length < old_args_length) {
1774
 
                JS_ReportOutOfMemory(cx);
1775
 
                return JS_FALSE;
1776
 
            }
1777
 
        }
1778
 
 
1779
 
        /* Add 1 for each joining comma and check for overflow (two ways). */
1780
 
        old_args_length = args_length;
1781
 
        args_length = old_args_length + n - 1;
1782
 
        if (args_length < old_args_length ||
1783
 
            args_length >= ~(size_t)0 / sizeof(jschar)) {
1784
 
            JS_ReportOutOfMemory(cx);
1785
 
            return JS_FALSE;
1786
 
        }
1787
 
 
1788
 
        /*
1789
 
         * Allocate a string to hold the concatenated arguments, including room
1790
 
         * for a terminating 0.  Mark cx->tempPool for later release, to free
1791
 
         * collected_args and its tokenstream in one swoop.
1792
 
         */
1793
 
        mark = JS_ARENA_MARK(&cx->tempPool);
1794
 
        JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
1795
 
                               (args_length+1) * sizeof(jschar));
1796
 
        if (!cp) {
1797
 
            js_ReportOutOfScriptQuota(cx);
1798
 
            return JS_FALSE;
1799
 
        }
1800
 
        collected_args = cp;
1801
 
 
1802
 
        /*
1803
 
         * Concatenate the arguments into the new string, separated by commas.
1804
 
         */
1805
 
        for (i = 0; i < n; i++) {
1806
 
            arg = JSVAL_TO_STRING(argv[i]);
1807
 
            arg_length = JSSTRING_LENGTH(arg);
1808
 
            (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
1809
 
            cp += arg_length;
1810
 
 
1811
 
            /* Add separating comma or terminating 0. */
1812
 
            *cp++ = (i + 1 < n) ? ',' : 0;
1813
 
        }
1814
 
 
1815
 
        /* Initialize a tokenstream that reads from the given string. */
1816
 
        if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
1817
 
                                NULL, filename, lineno)) {
1818
 
            JS_ARENA_RELEASE(&cx->tempPool, mark);
1819
 
            return JS_FALSE;
1820
 
        }
1821
 
 
1822
 
        /* The argument string may be empty or contain no tokens. */
1823
 
        tt = js_GetToken(cx, &ts);
1824
 
        if (tt != TOK_EOF) {
1825
 
            for (;;) {
1826
 
                /*
1827
 
                 * Check that it's a name.  This also implicitly guards against
1828
 
                 * TOK_ERROR, which was already reported.
1829
 
                 */
1830
 
                if (tt != TOK_NAME)
1831
 
                    goto after_args;
1832
 
 
1833
 
                /*
1834
 
                 * Get the atom corresponding to the name from the token
1835
 
                 * stream; we're assured at this point that it's a valid
1836
 
                 * identifier.
1837
 
                 */
1838
 
                atom = CURRENT_TOKEN(&ts).t_atom;
1839
 
 
1840
 
                /* Check for a duplicate parameter name. */
1841
 
                if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
1842
 
                    const char *name;
1843
 
 
1844
 
                    name = js_AtomToPrintableString(cx, atom);
1845
 
                    ok = name &&
1846
 
                         js_ReportCompileErrorNumber(cx, &ts, NULL,
1847
 
                                                     JSREPORT_WARNING |
1848
 
                                                     JSREPORT_STRICT,
1849
 
                                                     JSMSG_DUPLICATE_FORMAL,
1850
 
                                                     name);
1851
 
                    if (!ok)
1852
 
                        goto after_args;
1853
 
                }
1854
 
                if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG))
1855
 
                    goto after_args;
1856
 
 
1857
 
                /*
1858
 
                 * Get the next token.  Stop on end of stream.  Otherwise
1859
 
                 * insist on a comma, get another name, and iterate.
1860
 
                 */
1861
 
                tt = js_GetToken(cx, &ts);
1862
 
                if (tt == TOK_EOF)
1863
 
                    break;
1864
 
                if (tt != TOK_COMMA)
1865
 
                    goto after_args;
1866
 
                tt = js_GetToken(cx, &ts);
1867
 
            }
1868
 
        }
1869
 
 
1870
 
        state = OK;
1871
 
      after_args:
1872
 
        if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) {
1873
 
            /*
1874
 
             * Report "malformed formal parameter" iff no illegal char or
1875
 
             * similar scanner error was already reported.
1876
 
             */
1877
 
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1878
 
                                 JSMSG_BAD_FORMAL);
1879
 
        }
1880
 
        js_CloseTokenStream(cx, &ts);
1881
 
        JS_ARENA_RELEASE(&cx->tempPool, mark);
1882
 
        if (state != OK)
1883
 
            return JS_FALSE;
1884
 
    }
1885
 
 
1886
 
    if (argc) {
1887
 
        str = js_ValueToString(cx, argv[argc-1]);
1888
 
        if (!str)
1889
 
            return JS_FALSE;
1890
 
        argv[argc-1] = STRING_TO_JSVAL(str);
1891
 
    } else {
1892
 
        str = cx->runtime->emptyString;
1893
 
    }
1894
 
 
1895
 
    return js_CompileFunctionBody(cx, fun, principals,
1896
 
                                  JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
1897
 
                                  filename, lineno);
1898
 
}
1899
 
 
1900
 
JSObject *
1901
 
js_InitFunctionClass(JSContext *cx, JSObject *obj)
1902
 
{
1903
 
    JSObject *proto;
1904
 
    JSAtom *atom;
1905
 
    JSFunction *fun;
1906
 
 
1907
 
    proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
1908
 
                         function_props, function_methods, NULL, NULL);
1909
 
    if (!proto)
1910
 
        return NULL;
1911
 
    atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),
1912
 
                      0);
1913
 
    if (!atom)
1914
 
        goto bad;
1915
 
    fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
1916
 
    if (!fun)
1917
 
        goto bad;
1918
 
    fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0);
1919
 
    if (!fun->u.i.script)
1920
 
        goto bad;
1921
 
    fun->u.i.script->code[0] = JSOP_STOP;
1922
 
    return proto;
1923
 
 
1924
 
bad:
1925
 
    cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1926
 
    return NULL;
1927
 
}
1928
 
 
1929
 
JSObject *
1930
 
js_InitCallClass(JSContext *cx, JSObject *obj)
1931
 
{
1932
 
    JSObject *proto;
1933
 
 
1934
 
    proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
1935
 
                         NULL, NULL, NULL, NULL);
1936
 
    if (!proto)
1937
 
        return NULL;
1938
 
 
1939
 
    /*
1940
 
     * Null Call.prototype's proto slot so that Object.prototype.* does not
1941
 
     * pollute the scope of heavyweight functions.
1942
 
     */
1943
 
    OBJ_SET_PROTO(cx, proto, NULL);
1944
 
    return proto;
1945
 
}
1946
 
 
1947
 
JSFunction *
1948
 
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
1949
 
               uintN flags, JSObject *parent, JSAtom *atom)
1950
 
{
1951
 
    JSFunction *fun;
1952
 
    JSTempValueRooter tvr;
1953
 
 
1954
 
    /* If funobj is null, allocate an object for it. */
1955
 
    if (funobj) {
1956
 
        OBJ_SET_PARENT(cx, funobj, parent);
1957
 
    } else {
1958
 
        funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
1959
 
        if (!funobj)
1960
 
            return NULL;
1961
 
    }
1962
 
 
1963
 
    /* Protect fun from any potential GC callback. */
1964
 
    JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(funobj), &tvr);
1965
 
 
1966
 
    /*
1967
 
     * Allocate fun after allocating funobj so allocations in js_NewObject
1968
 
     * and hooks called from it do not wipe out fun from newborn[GCX_FUNCTION].
1969
 
     */
1970
 
    fun = (JSFunction *) js_NewGCThing(cx, GCX_FUNCTION, sizeof(JSFunction));
1971
 
    if (!fun)
1972
 
        goto out;
1973
 
 
1974
 
    /* Initialize all function members. */
1975
 
    fun->object = NULL;
1976
 
    fun->nargs = nargs;
1977
 
    fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED);
1978
 
    if (flags & JSFUN_INTERPRETED) {
1979
 
        JS_ASSERT(!native);
1980
 
        JS_ASSERT(nargs == 0);
1981
 
        fun->u.i.nvars = 0;
1982
 
        fun->u.i.spare = 0;
1983
 
        fun->u.i.script = NULL;
1984
 
#ifdef DEBUG
1985
 
        fun->u.i.names.taggedAtom = 0;
1986
 
#endif
1987
 
    } else {
1988
 
        fun->u.n.native = native;
1989
 
        fun->u.n.extra = 0;
1990
 
        fun->u.n.minargs = 0;
1991
 
        fun->u.n.clasp = NULL;
1992
 
    }
1993
 
    fun->atom = atom;
1994
 
 
1995
 
    /* Link fun to funobj and vice versa. */
1996
 
    if (!js_LinkFunctionObject(cx, fun, funobj)) {
1997
 
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1998
 
        fun = NULL;
1999
 
    }
2000
 
 
2001
 
out:
2002
 
    JS_POP_TEMP_ROOT(cx, &tvr);
2003
 
    return fun;
2004
 
}
2005
 
 
2006
 
static void
2007
 
TraceLocalNames(JSTracer *trc, JSFunction *fun);
2008
 
 
2009
 
void
2010
 
js_TraceFunction(JSTracer *trc, JSFunction *fun)
2011
 
{
2012
 
    if (fun->object)
2013
 
        JS_CALL_OBJECT_TRACER(trc, fun->object, "object");
2014
 
    if (fun->atom)
2015
 
        JS_CALL_STRING_TRACER(trc, ATOM_TO_STRING(fun->atom), "atom");
2016
 
    if (FUN_INTERPRETED(fun)) {
2017
 
        if (fun->u.i.script)
2018
 
            js_TraceScript(trc, fun->u.i.script);
2019
 
        TraceLocalNames(trc, fun);
2020
 
    }
2021
 
}
2022
 
 
2023
 
static void
2024
 
DestroyLocalNames(JSContext *cx, JSFunction *fun);
2025
 
 
2026
 
void
2027
 
js_FinalizeFunction(JSContext *cx, JSFunction *fun)
2028
 
{
2029
 
    /*
2030
 
     * Null-check of i.script is required since the parser sets interpreted
2031
 
     * very early.
2032
 
     */
2033
 
    if (FUN_INTERPRETED(fun)) {
2034
 
        if (fun->u.i.script)
2035
 
            js_DestroyScript(cx, fun->u.i.script);
2036
 
        DestroyLocalNames(cx, fun);
2037
 
    }
2038
 
}
2039
 
 
2040
 
JSObject *
2041
 
js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
2042
 
{
2043
 
    JSObject *newfunobj;
2044
 
    JSFunction *fun;
2045
 
 
2046
 
    JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
2047
 
    newfunobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
2048
 
    if (!newfunobj)
2049
 
        return NULL;
2050
 
    fun = GET_FUNCTION_PRIVATE(cx, funobj);
2051
 
    if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
2052
 
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;
2053
 
        return NULL;
2054
 
    }
2055
 
    return newfunobj;
2056
 
}
2057
 
 
2058
 
JSBool
2059
 
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
2060
 
{
2061
 
    if (!fun->object)
2062
 
        fun->object = funobj;
2063
 
    return JS_SetPrivate(cx, funobj, fun);
2064
 
}
2065
 
 
2066
 
JSFunction *
2067
 
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
2068
 
                  uintN nargs, uintN attrs)
2069
 
{
2070
 
    JSFunction *fun;
2071
 
 
2072
 
    fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
2073
 
    if (!fun)
2074
 
        return NULL;
2075
 
    if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2076
 
                             OBJECT_TO_JSVAL(fun->object),
2077
 
                             NULL, NULL,
2078
 
                             attrs & ~JSFUN_FLAGS_MASK, NULL)) {
2079
 
        return NULL;
2080
 
    }
2081
 
    return fun;
2082
 
}
2083
 
 
2084
 
#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2085
 
# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2086
 
#endif
2087
 
 
2088
 
JSFunction *
2089
 
js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
2090
 
{
2091
 
    jsval v;
2092
 
    JSObject *obj;
2093
 
 
2094
 
    v = *vp;
2095
 
    obj = NULL;
2096
 
    if (JSVAL_IS_OBJECT(v)) {
2097
 
        obj = JSVAL_TO_OBJECT(v);
2098
 
        if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
2099
 
            if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
2100
 
                return NULL;
2101
 
            obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
2102
 
        }
2103
 
    }
2104
 
    if (!obj) {
2105
 
        js_ReportIsNotFunction(cx, vp, flags);
2106
 
        return NULL;
2107
 
    }
2108
 
    return GET_FUNCTION_PRIVATE(cx, obj);
2109
 
}
2110
 
 
2111
 
JSObject *
2112
 
js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags)
2113
 
{
2114
 
    JSFunction *fun;
2115
 
    JSObject *funobj;
2116
 
    JSStackFrame *caller;
2117
 
    JSPrincipals *principals;
2118
 
 
2119
 
    if (VALUE_IS_FUNCTION(cx, *vp))
2120
 
        return JSVAL_TO_OBJECT(*vp);
2121
 
 
2122
 
    fun = js_ValueToFunction(cx, vp, flags);
2123
 
    if (!fun)
2124
 
        return NULL;
2125
 
    funobj = fun->object;
2126
 
    *vp = OBJECT_TO_JSVAL(funobj);
2127
 
 
2128
 
    caller = JS_GetScriptedCaller(cx, cx->fp);
2129
 
    if (caller) {
2130
 
        principals = caller->script->principals;
2131
 
    } else {
2132
 
        /* No scripted caller, don't allow access. */
2133
 
        principals = NULL;
2134
 
    }
2135
 
 
2136
 
    if (!js_CheckPrincipalsAccess(cx, funobj, principals,
2137
 
                                  fun->atom
2138
 
                                  ? fun->atom
2139
 
                                  : cx->runtime->atomState.anonymousAtom)) {
2140
 
        return NULL;
2141
 
    }
2142
 
    return funobj;
2143
 
}
2144
 
 
2145
 
JSObject *
2146
 
js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
2147
 
{
2148
 
    JSObject *callable;
2149
 
 
2150
 
    callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp);
2151
 
    if (callable &&
2152
 
        ((callable->map->ops == &js_ObjectOps)
2153
 
         ? OBJ_GET_CLASS(cx, callable)->call
2154
 
         : callable->map->ops->call)) {
2155
 
        *vp = OBJECT_TO_JSVAL(callable);
2156
 
    } else {
2157
 
        callable = js_ValueToFunctionObject(cx, vp, flags);
2158
 
    }
2159
 
    return callable;
2160
 
}
2161
 
 
2162
 
void
2163
 
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
2164
 
{
2165
 
    JSStackFrame *fp;
2166
 
    uintN error;
2167
 
    const char *name, *source;
2168
 
 
2169
 
    for (fp = cx->fp; fp && !fp->spbase; fp = fp->down)
2170
 
        continue;
2171
 
    name = NULL;
2172
 
    source = NULL;
2173
 
    if (flags & JSV2F_ITERATOR) {
2174
 
        error = JSMSG_BAD_ITERATOR;
2175
 
        name = js_iterator_str;
2176
 
        source = js_ValueToPrintableSource(cx, *vp);
2177
 
        if (!source)
2178
 
            return;
2179
 
    } else if (flags & JSV2F_CONSTRUCT) {
2180
 
        error = JSMSG_NOT_CONSTRUCTOR;
2181
 
    } else {
2182
 
        error = JSMSG_NOT_FUNCTION;
2183
 
    }
2184
 
 
2185
 
    js_ReportValueError3(cx, error,
2186
 
                         (fp && fp->spbase <= vp && vp < fp->sp)
2187
 
                         ? vp - fp->sp
2188
 
                         : (flags & JSV2F_SEARCH_STACK)
2189
 
                         ? JSDVG_SEARCH_STACK
2190
 
                         : JSDVG_IGNORE_STACK,
2191
 
                         *vp, NULL,
2192
 
                         name, source);
2193
 
}
2194
 
 
2195
 
/*
2196
 
 * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
2197
 
 * their name are stored as the JSLocalNames.array.
2198
 
 */
2199
 
#define MAX_ARRAY_LOCALS 8
2200
 
 
2201
 
JS_STATIC_ASSERT(2 <= MAX_ARRAY_LOCALS);
2202
 
JS_STATIC_ASSERT(MAX_ARRAY_LOCALS < JS_BITMASK(16));
2203
 
 
2204
 
/*
2205
 
 * We use the lowest bit of the string atom to distinguish const from var
2206
 
 * name when there is only single name or when names are stored as an array.
2207
 
 */
2208
 
JS_STATIC_ASSERT((JSVAL_STRING & 1) == 0);
2209
 
 
2210
 
/*
2211
 
 * When we use a hash table to store the local names, we use a singly linked
2212
 
 * list to record the indexes of duplicated parameter names to preserve the
2213
 
 * duplicates for the decompiler.
2214
 
 */
2215
 
typedef struct JSNameIndexPair JSNameIndexPair;
2216
 
 
2217
 
struct JSNameIndexPair {
2218
 
    JSAtom          *name;
2219
 
    uint16          index;
2220
 
    JSNameIndexPair *link;
2221
 
};
2222
 
 
2223
 
struct JSLocalNameMap {
2224
 
    JSDHashTable    names;
2225
 
    JSNameIndexPair *lastdup;
2226
 
};
2227
 
 
2228
 
typedef struct JSLocalNameHashEntry {
2229
 
    JSDHashEntryHdr hdr;
2230
 
    JSAtom          *name;
2231
 
    uint16          index;
2232
 
    uint8           localKind;
2233
 
} JSLocalNameHashEntry;
2234
 
 
2235
 
static void
2236
 
FreeLocalNameHash(JSContext *cx, JSLocalNameMap *map)
2237
 
{
2238
 
    JSNameIndexPair *dup, *next;
2239
 
 
2240
 
    for (dup = map->lastdup; dup; dup = next) {
2241
 
        next = dup->link;
2242
 
        JS_free(cx, dup);
2243
 
    }
2244
 
    JS_DHashTableFinish(&map->names);
2245
 
    JS_free(cx, map);
2246
 
}
2247
 
 
2248
 
static JSBool
2249
 
HashLocalName(JSContext *cx, JSLocalNameMap *map, JSAtom *name,
2250
 
              JSLocalKind localKind, uintN index)
2251
 
{
2252
 
    JSLocalNameHashEntry *entry;
2253
 
    JSNameIndexPair *dup;
2254
 
 
2255
 
    JS_ASSERT(index <= JS_BITMASK(16));
2256
 
#if JS_HAS_DESTRUCTURING
2257
 
    if (!name) {
2258
 
        /* A destructuring pattern does not need a hash entry. */
2259
 
        JS_ASSERT(localKind == JSLOCAL_ARG);
2260
 
        return JS_TRUE;
2261
 
    }
2262
 
#endif
2263
 
    JS_ASSERT(ATOM_IS_STRING(name));
2264
 
    entry = (JSLocalNameHashEntry *)
2265
 
            JS_DHashTableOperate(&map->names, name, JS_DHASH_ADD);
2266
 
    if (!entry) {
2267
 
        JS_ReportOutOfMemory(cx);
2268
 
        return JS_FALSE;
2269
 
    }
2270
 
    if (entry->name) {
2271
 
        JS_ASSERT(entry->name == name);
2272
 
        JS_ASSERT(entry->localKind == JSLOCAL_ARG);
2273
 
        dup = (JSNameIndexPair *) JS_malloc(cx, sizeof *dup);
2274
 
        if (!dup)
2275
 
            return JS_FALSE;
2276
 
        dup->name = entry->name;
2277
 
        dup->index = entry->index;
2278
 
        dup->link = map->lastdup;
2279
 
        map->lastdup = dup;
2280
 
    }
2281
 
    entry->name = name;
2282
 
    entry->index = (uint16) index;
2283
 
    entry->localKind = (uint8) localKind;
2284
 
    return JS_TRUE;
2285
 
}
2286
 
 
2287
 
JSBool
2288
 
js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind)
2289
 
{
2290
 
    jsuword taggedAtom;
2291
 
    uint16 *indexp;
2292
 
    uintN n, i;
2293
 
    jsuword *array;
2294
 
    JSLocalNameMap *map;
2295
 
 
2296
 
    JS_ASSERT(FUN_INTERPRETED(fun));
2297
 
    JS_ASSERT(!fun->u.i.script);
2298
 
    JS_ASSERT(((jsuword) atom & 1) == 0);
2299
 
    taggedAtom = (jsuword) atom;
2300
 
    if (kind == JSLOCAL_ARG) {
2301
 
        indexp = &fun->nargs;
2302
 
    } else {
2303
 
        indexp = &fun->u.i.nvars;
2304
 
        if (kind == JSLOCAL_CONST)
2305
 
            taggedAtom |= 1;
2306
 
        else
2307
 
            JS_ASSERT(kind == JSLOCAL_VAR);
2308
 
    }
2309
 
    n = fun->nargs + fun->u.i.nvars;
2310
 
    if (n == 0) {
2311
 
        JS_ASSERT(fun->u.i.names.taggedAtom == 0);
2312
 
        fun->u.i.names.taggedAtom = taggedAtom;
2313
 
    } else if (n < MAX_ARRAY_LOCALS) {
2314
 
        if (n > 1) {
2315
 
            array = fun->u.i.names.array;
2316
 
        } else {
2317
 
            array = (jsuword *) JS_malloc(cx, MAX_ARRAY_LOCALS * sizeof *array);
2318
 
            if (!array)
2319
 
                return JS_FALSE;
2320
 
            array[0] = fun->u.i.names.taggedAtom;
2321
 
            fun->u.i.names.array = array;
2322
 
        }
2323
 
        if (kind == JSLOCAL_ARG) {
2324
 
            /*
2325
 
             * A destructuring argument pattern adds variables, not arguments,
2326
 
             * so for the following arguments nvars != 0.
2327
 
             */
2328
 
#if JS_HAS_DESTRUCTURING
2329
 
            if (fun->u.i.nvars != 0) {
2330
 
                memmove(array + fun->nargs + 1, array + fun->nargs,
2331
 
                        fun->u.i.nvars * sizeof *array);
2332
 
            }
2333
 
#else
2334
 
            JS_ASSERT(fun->u.i.nvars == 0);
2335
 
#endif
2336
 
            array[fun->nargs] = taggedAtom;
2337
 
        } else {
2338
 
            array[n] = taggedAtom;
2339
 
        }
2340
 
    } else if (n == MAX_ARRAY_LOCALS) {
2341
 
        array = fun->u.i.names.array;
2342
 
        map = (JSLocalNameMap *) JS_malloc(cx, sizeof *map);
2343
 
        if (!map)
2344
 
            return JS_FALSE;
2345
 
        if (!JS_DHashTableInit(&map->names, JS_DHashGetStubOps(),
2346
 
                               NULL, sizeof(JSLocalNameHashEntry),
2347
 
                               JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS
2348
 
                                                         * 2))) {
2349
 
            JS_ReportOutOfMemory(cx);
2350
 
            JS_free(cx, map);
2351
 
            return JS_FALSE;
2352
 
        }
2353
 
 
2354
 
        map->lastdup = NULL;
2355
 
        for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {
2356
 
            taggedAtom = array[i];
2357
 
            if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1),
2358
 
                               (i < fun->nargs)
2359
 
                               ? JSLOCAL_ARG
2360
 
                               : (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR,
2361
 
                               (i < fun->nargs) ? i : i - fun->nargs)) {
2362
 
                FreeLocalNameHash(cx, map);
2363
 
                return JS_FALSE;
2364
 
            }
2365
 
        }
2366
 
        if (!HashLocalName(cx, map, atom, kind, *indexp)) {
2367
 
            FreeLocalNameHash(cx, map);
2368
 
            return JS_FALSE;
2369
 
        }
2370
 
 
2371
 
        /*
2372
 
         * At this point the entry is added and we cannot fail. It is time
2373
 
         * to replace fun->u.i.names with the built map.
2374
 
         */
2375
 
        fun->u.i.names.map = map;
2376
 
        JS_free(cx, array);
2377
 
    } else {
2378
 
        if (*indexp == JS_BITMASK(16)) {
2379
 
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2380
 
                                 (kind == JSLOCAL_ARG)
2381
 
                                 ? JSMSG_TOO_MANY_FUN_ARGS
2382
 
                                 : JSMSG_TOO_MANY_FUN_VARS);
2383
 
            return JS_FALSE;
2384
 
        }
2385
 
        if (!HashLocalName(cx, fun->u.i.names.map, atom, kind, *indexp))
2386
 
            return JS_FALSE;
2387
 
    }
2388
 
 
2389
 
    /* Update the argument or variable counter. */
2390
 
    ++*indexp;
2391
 
    return JS_TRUE;
2392
 
}
2393
 
 
2394
 
JSLocalKind
2395
 
js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp)
2396
 
{
2397
 
    uintN n, i;
2398
 
    jsuword *array;
2399
 
    JSLocalNameHashEntry *entry;
2400
 
 
2401
 
    JS_ASSERT(FUN_INTERPRETED(fun));
2402
 
    n = fun->nargs + fun->u.i.nvars;
2403
 
    if (n == 0)
2404
 
        return JSLOCAL_NONE;
2405
 
    if (n <= MAX_ARRAY_LOCALS) {
2406
 
        array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2407
 
 
2408
 
        /* Search from the tail to pick up the last duplicated name. */
2409
 
        i = n;
2410
 
        do {
2411
 
            --i;
2412
 
            if (atom == (JSAtom *) (array[i] & ~1)) {
2413
 
                if (i < fun->nargs) {
2414
 
                    if (indexp)
2415
 
                        *indexp = i;
2416
 
                    return JSLOCAL_ARG;
2417
 
                }
2418
 
                if (indexp)
2419
 
                    *indexp = i - fun->nargs;
2420
 
                return (array[i] & 1) ? JSLOCAL_CONST : JSLOCAL_VAR;
2421
 
            }
2422
 
        } while (i != 0);
2423
 
    } else {
2424
 
        entry = (JSLocalNameHashEntry *)
2425
 
                JS_DHashTableOperate(&fun->u.i.names.map->names, atom,
2426
 
                                     JS_DHASH_LOOKUP);
2427
 
        if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) {
2428
 
            JS_ASSERT(entry->localKind != JSLOCAL_NONE);
2429
 
            if (indexp)
2430
 
                *indexp = entry->index;
2431
 
            return (JSLocalKind) entry->localKind;
2432
 
        }
2433
 
    }
2434
 
    return JSLOCAL_NONE;
2435
 
}
2436
 
 
2437
 
typedef struct JSGetLocalNamesArgs {
2438
 
    JSFunction      *fun;
2439
 
    JSAtom          **names;
2440
 
    uint32          *bitmap;
2441
 
#ifdef DEBUG
2442
 
    uintN           nCopiedArgs;
2443
 
    uintN           nCopiedVars;
2444
 
#endif
2445
 
} JSGetLocalNamesArgs;
2446
 
 
2447
 
#define SET_BIT32(bitmap, bit)                                                \
2448
 
    ((bitmap)[(bit) >> JS_BITS_PER_UINT32_LOG2] |=                            \
2449
 
         JS_BIT((bit) & (JS_BITS_PER_UINT32 - 1)))
2450
 
 
2451
 
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
2452
 
get_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2453
 
                           uint32 number, void *arg)
2454
 
{
2455
 
    JSLocalNameHashEntry *entry;
2456
 
    JSGetLocalNamesArgs *args;
2457
 
    uint i;
2458
 
 
2459
 
    entry = (JSLocalNameHashEntry *) hdr;
2460
 
    args = (JSGetLocalNamesArgs *) arg;
2461
 
    JS_ASSERT(entry->name);
2462
 
    if (entry->localKind == JSLOCAL_ARG) {
2463
 
        JS_ASSERT(entry->index < args->fun->nargs);
2464
 
        JS_ASSERT(args->nCopiedArgs++ < args->fun->nargs);
2465
 
        i = entry->index;
2466
 
    } else {
2467
 
        JS_ASSERT(entry->localKind == JSLOCAL_VAR ||
2468
 
                  entry->localKind == JSLOCAL_CONST);
2469
 
        JS_ASSERT(entry->index < args->fun->u.i.nvars);
2470
 
        JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars);
2471
 
        i = args->fun->nargs + entry->index;
2472
 
    }
2473
 
    args->names[i] = entry->name;
2474
 
    if (args->bitmap && entry->localKind != JSLOCAL_VAR)
2475
 
        SET_BIT32(args->bitmap, i);
2476
 
    return JS_DHASH_NEXT;
2477
 
}
2478
 
 
2479
 
JSAtom **
2480
 
js_GetLocalNames(JSContext *cx, JSFunction *fun, JSArenaPool *pool,
2481
 
                 uint32 **bitmap)
2482
 
{
2483
 
    uintN n, i;
2484
 
    size_t allocsize;
2485
 
    JSAtom **names;
2486
 
    jsuword *array;
2487
 
    JSLocalNameMap *map;
2488
 
    JSGetLocalNamesArgs args;
2489
 
    JSNameIndexPair *dup;
2490
 
 
2491
 
    JS_ASSERT(FUN_INTERPRETED(fun));
2492
 
    JS_ASSERT(OBJ_IS_NATIVE(fun->object));
2493
 
    n = fun->nargs + fun->u.i.nvars;
2494
 
    JS_ASSERT(n != 0);
2495
 
    allocsize = n * sizeof *names;
2496
 
    if (bitmap)
2497
 
        allocsize += JS_HOWMANY(n, JS_BITS_PER_UINT32) * sizeof(uint32);
2498
 
    JS_ARENA_ALLOCATE_CAST(names, JSAtom **, pool, allocsize);
2499
 
    if (!names) {
2500
 
        js_ReportOutOfScriptQuota(cx);
2501
 
        return NULL;
2502
 
    }
2503
 
 
2504
 
#if JS_HAS_DESTRUCTURING
2505
 
    /* Some parameter names can be NULL due to destructuring patterns. */
2506
 
    memset(names, 0, fun->nargs * sizeof *names);
2507
 
#endif
2508
 
    if (bitmap) {
2509
 
        *bitmap = (uint32 *) (names + n);
2510
 
        memset(*bitmap, 0, JS_HOWMANY(n, JS_BITS_PER_UINT32) * sizeof(uint32));
2511
 
    }
2512
 
 
2513
 
    if (n <= MAX_ARRAY_LOCALS) {
2514
 
        array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2515
 
 
2516
 
        i = n;
2517
 
        do {
2518
 
            --i;
2519
 
            names[i] = (JSAtom *) (array[i] & ~1);
2520
 
            if (bitmap &&
2521
 
                (i < fun->nargs ? array[i] != 0 : array[i] & 1)) {
2522
 
                SET_BIT32(*bitmap, i);
2523
 
            }
2524
 
        } while (i != 0);
2525
 
    } else {
2526
 
        map = fun->u.i.names.map;
2527
 
        args.fun = fun;
2528
 
        args.names = names;
2529
 
        args.bitmap = bitmap ? *bitmap : NULL;
2530
 
#ifdef DEBUG
2531
 
        args.nCopiedArgs = 0;
2532
 
        args.nCopiedVars = 0;
2533
 
#endif
2534
 
        JS_DHashTableEnumerate(&map->names, get_local_names_enumerator, &args);
2535
 
        for (dup = map->lastdup; dup; dup = dup->link) {
2536
 
            JS_ASSERT(dup->index < fun->nargs);
2537
 
            JS_ASSERT(args.nCopiedArgs++ < fun->nargs);
2538
 
            names[dup->index] = dup->name;
2539
 
            if (bitmap)
2540
 
                SET_BIT32(*bitmap, dup->index);
2541
 
        }
2542
 
#if !JS_HAS_DESTRUCTURING
2543
 
        JS_ASSERT(args.nCopiedArgs == fun->nargs);
2544
 
#endif
2545
 
        JS_ASSERT(args.nCopiedVars == fun->u.i.nvars);
2546
 
    }
2547
 
 
2548
 
    return names;
2549
 
}
2550
 
 
2551
 
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
2552
 
trace_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2553
 
                             uint32 number, void *arg)
2554
 
{
2555
 
    JSLocalNameHashEntry *entry;
2556
 
    JSTracer *trc;
2557
 
 
2558
 
    entry = (JSLocalNameHashEntry *) hdr;
2559
 
    JS_ASSERT(entry->name);
2560
 
    trc = (JSTracer *) arg;
2561
 
    JS_SET_TRACING_INDEX(trc,
2562
 
                         entry->localKind == JSLOCAL_ARG ? "arg" : "var",
2563
 
                         entry->index);
2564
 
    JS_CallTracer(trc, ATOM_TO_STRING(entry->name), JSTRACE_STRING);
2565
 
    return JS_DHASH_NEXT;
2566
 
}
2567
 
 
2568
 
static void
2569
 
TraceLocalNames(JSTracer *trc, JSFunction *fun)
2570
 
{
2571
 
    uintN n, i;
2572
 
    JSAtom *atom;
2573
 
    jsuword *array;
2574
 
 
2575
 
    JS_ASSERT(FUN_INTERPRETED(fun));
2576
 
    n = fun->nargs + fun->u.i.nvars;
2577
 
    if (n == 0)
2578
 
        return;
2579
 
    if (n <= MAX_ARRAY_LOCALS) {
2580
 
        array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2581
 
        i = n;
2582
 
        do {
2583
 
            --i;
2584
 
            atom = (JSAtom *) (array[i] & ~1);
2585
 
            if (atom) {
2586
 
                JS_SET_TRACING_INDEX(trc,
2587
 
                                     i < fun->nargs ? "arg" : "var",
2588
 
                                     i < fun->nargs ? i : i - fun->nargs);
2589
 
                JS_CallTracer(trc, ATOM_TO_STRING(atom), JSTRACE_STRING);
2590
 
            }
2591
 
        } while (i != 0);
2592
 
    } else {
2593
 
        JS_DHashTableEnumerate(&fun->u.i.names.map->names,
2594
 
                               trace_local_names_enumerator, trc);
2595
 
 
2596
 
        /*
2597
 
         * No need to trace the list of duplicates in map->lastdup as the
2598
 
         * names there are traced when enumerating the hash table.
2599
 
         */
2600
 
    }
2601
 
}
2602
 
 
2603
 
void
2604
 
DestroyLocalNames(JSContext *cx, JSFunction *fun)
2605
 
{
2606
 
    uintN n;
2607
 
 
2608
 
    n = fun->nargs + fun->u.i.nvars;
2609
 
    if (n <= 1)
2610
 
        return;
2611
 
    if (n <= MAX_ARRAY_LOCALS)
2612
 
        JS_free(cx, fun->u.i.names.array);
2613
 
    else
2614
 
        FreeLocalNameHash(cx, fun->u.i.names.map);
2615
 
}
2616
 
 
2617
 
void
2618
 
js_FreezeLocalNames(JSContext *cx, JSFunction *fun)
2619
 
{
2620
 
    uintN n;
2621
 
    jsuword *array;
2622
 
 
2623
 
    JS_ASSERT(FUN_INTERPRETED(fun));
2624
 
    JS_ASSERT(!fun->u.i.script);
2625
 
    n = fun->nargs + fun->u.i.nvars;
2626
 
    if (2 <= n && n < MAX_ARRAY_LOCALS) {
2627
 
        /* Shrink over-allocated array ignoring realloc failures. */
2628
 
        array = (jsuword *) JS_realloc(cx, fun->u.i.names.array,
2629
 
                                       n * sizeof *array);
2630
 
        if (array)
2631
 
            fun->u.i.names.array = array;
2632
 
    }
2633
 
}