~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

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
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
6
 * The contents of this file are subject to the Mozilla Public License Version
 
7
 * 1.1 (the "License"); you may not use this file except in compliance with
 
8
 * the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/MPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is Mozilla Communicator client code, released
 
17
 * March 31, 1998.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1998
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 
28
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the MPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the MPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
/*
 
41
 * JS function support.
 
42
 */
 
43
#include "jsstddef.h"
 
44
#include <string.h>
 
45
#include "jstypes.h"
 
46
#include "jsbit.h"
 
47
#include "jsutil.h" /* Added by JSIFY */
 
48
#include "jsapi.h"
 
49
#include "jsarray.h"
 
50
#include "jsatom.h"
 
51
#include "jscntxt.h"
 
52
#include "jsconfig.h"
 
53
#include "jsdbgapi.h"
 
54
#include "jsfun.h"
 
55
#include "jsgc.h"
 
56
#include "jsinterp.h"
 
57
#include "jslock.h"
 
58
#include "jsnum.h"
 
59
#include "jsobj.h"
 
60
#include "jsopcode.h"
 
61
#include "jsparse.h"
 
62
#include "jsscan.h"
 
63
#include "jsscope.h"
 
64
#include "jsscript.h"
 
65
#include "jsstr.h"
 
66
#include "jsexn.h"
 
67
 
 
68
/* Generic function/call/arguments tinyids -- also reflected bit numbers. */
 
69
enum {
 
70
    CALL_ARGUMENTS  = -1,       /* predefined arguments local variable */
 
71
    CALL_CALLEE     = -2,       /* reference to active function's object */
 
72
    ARGS_LENGTH     = -3,       /* number of actual args, arity if inactive */
 
73
    ARGS_CALLEE     = -4,       /* reference from arguments to active funobj */
 
74
    FUN_ARITY       = -5,       /* number of formal parameters; desired argc */
 
75
    FUN_NAME        = -6,       /* function name, "" if anonymous */
 
76
    FUN_CALLER      = -7        /* Function.prototype.caller, backward compat */
 
77
};
 
78
 
 
79
#if JSFRAME_OVERRIDE_BITS < 8
 
80
# error "not enough override bits in JSStackFrame.flags!"
 
81
#endif
 
82
 
 
83
#define TEST_OVERRIDE_BIT(fp, tinyid) \
 
84
    ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
 
85
 
 
86
#define SET_OVERRIDE_BIT(fp, tinyid) \
 
87
    ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
 
88
 
 
89
#if JS_HAS_ARGS_OBJECT
 
90
 
 
91
JSBool
 
92
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
 
93
{
 
94
    JSObject *argsobj;
 
95
 
 
96
    if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
 
97
        JS_ASSERT(fp->callobj);
 
98
        return OBJ_GET_PROPERTY(cx, fp->callobj,
 
99
                                (jsid) cx->runtime->atomState.argumentsAtom,
 
100
                                vp);
 
101
    }
 
102
    argsobj = js_GetArgsObject(cx, fp);
 
103
    if (!argsobj)
 
104
        return JS_FALSE;
 
105
    *vp = OBJECT_TO_JSVAL(argsobj);
 
106
    return JS_TRUE;
 
107
}
 
108
 
 
109
#define MAXARGS(fp)     ((fp)->fun ? JS_MAX((fp)->argc, (fp)->fun->nargs)     \
 
110
                                   : (fp)->argc)
 
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 = MAXARGS(fp);
 
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 (MAXARGS(fp) <= 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,
 
176
                   JSObject **objp, jsval *vp)
 
177
{
 
178
    jsval val;
 
179
    JSObject *obj;
 
180
    uintN slot;
 
181
 
 
182
    if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
 
183
        JS_ASSERT(fp->callobj);
 
184
        if (!OBJ_GET_PROPERTY(cx, fp->callobj,
 
185
                              (jsid) cx->runtime->atomState.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
        *objp = obj;
 
197
        return OBJ_GET_PROPERTY(cx, obj, id, vp);
 
198
    }
 
199
 
 
200
    *objp = NULL;
 
201
    *vp = JSVAL_VOID;
 
202
    if (JSVAL_IS_INT(id)) {
 
203
        slot = (uintN) JSVAL_TO_INT(id);
 
204
        if (slot < MAXARGS(fp)) {
 
205
            if (fp->argsobj && ArgWasDeleted(cx, fp, slot))
 
206
                return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
 
207
            *vp = fp->argv[slot];
 
208
        }
 
209
    } else {
 
210
        if (id == (jsid) cx->runtime->atomState.lengthAtom) {
 
211
            if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH))
 
212
                return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
 
213
            *vp = INT_TO_JSVAL((jsint) fp->argc);
 
214
        }
 
215
    }
 
216
    return JS_TRUE;
 
217
}
 
218
 
 
219
JSObject *
 
220
js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
 
221
{
 
222
    JSObject *argsobj;
 
223
 
 
224
    /* Create an arguments object for fp only if it lacks one. */
 
225
    argsobj = fp->argsobj;
 
226
    if (argsobj)
 
227
        return argsobj;
 
228
 
 
229
    /* Link the new object to fp so it can get actual argument values. */
 
230
    argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL);
 
231
    if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
 
232
        cx->newborn[GCX_OBJECT] = NULL;
 
233
        return NULL;
 
234
    }
 
235
    fp->argsobj = argsobj;
 
236
    return argsobj;
 
237
}
 
238
 
 
239
static JSBool
 
240
args_enumerate(JSContext *cx, JSObject *obj);
 
241
 
 
242
JSBool
 
243
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
 
244
{
 
245
    JSObject *argsobj;
 
246
    jsval bmapval, rval;
 
247
    JSBool ok;
 
248
    JSRuntime *rt;
 
249
 
 
250
    /*
 
251
     * Reuse args_enumerate here to reflect fp's actual arguments as indexed
 
252
     * elements of argsobj.  Do this first, before clearing and freeing the
 
253
     * deleted argument slot bitmap, because args_enumerate depends on that.
 
254
     */
 
255
    argsobj = fp->argsobj;
 
256
    ok = args_enumerate(cx, argsobj);
 
257
 
 
258
    /*
 
259
     * Now clear the deleted argument number bitmap slot and free the bitmap,
 
260
     * if one was actually created due to 'delete arguments[0]' or similar.
 
261
     */
 
262
    (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
 
263
    if (!JSVAL_IS_VOID(bmapval)) {
 
264
        JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
 
265
        if (MAXARGS(fp) > JSVAL_INT_BITS)
 
266
            JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
 
267
    }
 
268
 
 
269
    /*
 
270
     * Now get the prototype properties so we snapshot fp->fun and fp->argc
 
271
     * before fp goes away.
 
272
     */
 
273
    rt = cx->runtime;
 
274
    ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
 
275
    ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval);
 
276
    ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
 
277
    ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval);
 
278
 
 
279
    /*
 
280
     * Clear the private pointer to fp, which is about to go away (js_Invoke).
 
281
     * Do this last because the args_enumerate and js_GetProperty calls above
 
282
     * need to follow the private slot to find fp.
 
283
     */
 
284
    ok &= JS_SetPrivate(cx, argsobj, NULL);
 
285
    fp->argsobj = NULL;
 
286
    return ok;
 
287
}
 
288
 
 
289
static JSBool
 
290
args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
291
{
 
292
    jsint slot;
 
293
    JSStackFrame *fp;
 
294
 
 
295
    if (!JSVAL_IS_INT(id))
 
296
        return JS_TRUE;
 
297
    fp = (JSStackFrame *)
 
298
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
 
299
    if (!fp)
 
300
        return JS_TRUE;
 
301
    JS_ASSERT(fp->argsobj);
 
302
 
 
303
    slot = JSVAL_TO_INT(id);
 
304
    switch (slot) {
 
305
      case ARGS_CALLEE:
 
306
      case ARGS_LENGTH:
 
307
        SET_OVERRIDE_BIT(fp, slot);
 
308
        break;
 
309
 
 
310
      default:
 
311
        if ((uintN)slot < MAXARGS(fp) && !MarkArgDeleted(cx, fp, slot))
 
312
            return JS_FALSE;
 
313
        break;
 
314
    }
 
315
    return JS_TRUE;
 
316
}
 
317
 
 
318
static JSBool
 
319
args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
320
{
 
321
    jsint slot;
 
322
    JSStackFrame *fp;
 
323
 
 
324
    if (!JSVAL_IS_INT(id))
 
325
        return JS_TRUE;
 
326
    fp = (JSStackFrame *)
 
327
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
 
328
    if (!fp)
 
329
        return JS_TRUE;
 
330
    JS_ASSERT(fp->argsobj);
 
331
 
 
332
    slot = JSVAL_TO_INT(id);
 
333
    switch (slot) {
 
334
      case ARGS_CALLEE:
 
335
        if (!TEST_OVERRIDE_BIT(fp, slot))
 
336
            *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
 
337
        break;
 
338
 
 
339
      case ARGS_LENGTH:
 
340
        if (!TEST_OVERRIDE_BIT(fp, slot))
 
341
            *vp = INT_TO_JSVAL((jsint)fp->argc);
 
342
        break;
 
343
 
 
344
      default:
 
345
        if ((uintN)slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot))
 
346
            *vp = fp->argv[slot];
 
347
        break;
 
348
    }
 
349
    return JS_TRUE;
 
350
}
 
351
 
 
352
static JSBool
 
353
args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
354
{
 
355
    JSStackFrame *fp;
 
356
    jsint slot;
 
357
 
 
358
    if (!JSVAL_IS_INT(id))
 
359
        return JS_TRUE;
 
360
    fp = (JSStackFrame *)
 
361
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
 
362
    if (!fp)
 
363
        return JS_TRUE;
 
364
    JS_ASSERT(fp->argsobj);
 
365
 
 
366
    slot = JSVAL_TO_INT(id);
 
367
    switch (slot) {
 
368
      case ARGS_CALLEE:
 
369
      case ARGS_LENGTH:
 
370
        SET_OVERRIDE_BIT(fp, slot);
 
371
        break;
 
372
 
 
373
      default:
 
374
        if ((uintN)slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot))
 
375
            fp->argv[slot] = *vp;
 
376
        break;
 
377
    }
 
378
    return JS_TRUE;
 
379
}
 
380
 
 
381
static JSBool
 
382
args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
 
383
             JSObject **objp)
 
384
{
 
385
    JSStackFrame *fp;
 
386
    uintN slot;
 
387
    JSString *str;
 
388
    JSAtom *atom;
 
389
    intN tinyid;
 
390
    jsval value;
 
391
 
 
392
    *objp = NULL;
 
393
    fp = (JSStackFrame *)
 
394
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
 
395
    if (!fp)
 
396
        return JS_TRUE;
 
397
    JS_ASSERT(fp->argsobj);
 
398
 
 
399
    if (JSVAL_IS_INT(id)) {
 
400
        slot = JSVAL_TO_INT(id);
 
401
        if (slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot)) {
 
402
            /* XXX ECMA specs DontEnum, contrary to other array-like objects */
 
403
            if (!js_DefineProperty(cx, obj, (jsid) id, fp->argv[slot],
 
404
                                   args_getProperty, args_setProperty,
 
405
                                   JSVERSION_IS_ECMA(cx->version)
 
406
                                   ? 0
 
407
                                   : JSPROP_ENUMERATE,
 
408
                                   NULL)) {
 
409
                return JS_FALSE;
 
410
            }
 
411
            *objp = obj;
 
412
        }
 
413
    } else {
 
414
        str = JSVAL_TO_STRING(id);
 
415
        atom = cx->runtime->atomState.lengthAtom;
 
416
        if (str == ATOM_TO_STRING(atom)) {
 
417
            tinyid = ARGS_LENGTH;
 
418
            value = INT_TO_JSVAL(fp->argc);
 
419
        } else {
 
420
            atom = cx->runtime->atomState.calleeAtom;
 
421
            if (str == ATOM_TO_STRING(atom)) {
 
422
                tinyid = ARGS_CALLEE;
 
423
                value = fp->argv ? fp->argv[-2]
 
424
                                 : OBJECT_TO_JSVAL(fp->fun->object);
 
425
            } else {
 
426
                atom = NULL;
 
427
 
 
428
                /* Quell GCC overwarnings. */
 
429
                tinyid = 0;
 
430
                value = JSVAL_NULL;
 
431
            }
 
432
        }
 
433
 
 
434
        if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
 
435
            if (!js_DefineNativeProperty(cx, obj, (jsid) atom, value,
 
436
                                         args_getProperty, args_setProperty, 0,
 
437
                                         SPROP_HAS_SHORTID, tinyid, NULL)) {
 
438
                return JS_FALSE;
 
439
            }
 
440
            *objp = obj;
 
441
        }
 
442
    }
 
443
 
 
444
    return JS_TRUE;
 
445
}
 
446
 
 
447
static JSBool
 
448
args_enumerate(JSContext *cx, JSObject *obj)
 
449
{
 
450
    JSStackFrame *fp;
 
451
    JSObject *pobj;
 
452
    JSProperty *prop;
 
453
    uintN slot, nargs;
 
454
 
 
455
    fp = (JSStackFrame *)
 
456
         JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
 
457
    if (!fp)
 
458
        return JS_TRUE;
 
459
    JS_ASSERT(fp->argsobj);
 
460
 
 
461
    /*
 
462
     * Trigger reflection with value snapshot in args_resolve using a series
 
463
     * of js_LookupProperty calls.  We handle length, callee, and the indexed
 
464
     * argument properties.  We know that args_resolve covers all these cases
 
465
     * and creates direct properties of obj, but that it may fail to resolve
 
466
     * length or callee if overridden.
 
467
     */
 
468
    if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.lengthAtom,
 
469
                           &pobj, &prop)) {
 
470
        return JS_FALSE;
 
471
    }
 
472
    if (prop)
 
473
        OBJ_DROP_PROPERTY(cx, pobj, prop);
 
474
 
 
475
    if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.calleeAtom,
 
476
                           &pobj, &prop)) {
 
477
        return JS_FALSE;
 
478
    }
 
479
    if (prop)
 
480
        OBJ_DROP_PROPERTY(cx, pobj, prop);
 
481
 
 
482
    nargs = MAXARGS(fp);
 
483
    for (slot = 0; slot < nargs; slot++) {
 
484
        if (!js_LookupProperty(cx, obj, (jsid) INT_TO_JSVAL((jsint)slot),
 
485
                               &pobj, &prop)) {
 
486
            return JS_FALSE;
 
487
        }
 
488
        if (prop)
 
489
            OBJ_DROP_PROPERTY(cx, pobj, prop);
 
490
    }
 
491
    return JS_TRUE;
 
492
}
 
493
 
 
494
/*
 
495
 * The Arguments class is not initialized via JS_InitClass, and must not be,
 
496
 * because its name is "Object".  Per ECMA, that causes instances of it to
 
497
 * delegate to the object named by Object.prototype.  It also ensures that
 
498
 * arguments.toString() returns "[object Object]".
 
499
 *
 
500
 * The JSClass functions below collaborate to lazily reflect and synchronize
 
501
 * actual argument values, argument count, and callee function object stored
 
502
 * in a JSStackFrame with their corresponding property values in the frame's
 
503
 * arguments object.
 
504
 */
 
505
JSClass js_ArgumentsClass = {
 
506
    js_Object_str,
 
507
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1),
 
508
    JS_PropertyStub,  args_delProperty,
 
509
    args_getProperty, args_setProperty,
 
510
    args_enumerate,   (JSResolveOp) args_resolve,
 
511
    JS_ConvertStub,   JS_FinalizeStub,
 
512
    JSCLASS_NO_OPTIONAL_MEMBERS
 
513
};
 
514
 
 
515
#endif /* JS_HAS_ARGS_OBJECT */
 
516
 
 
517
#if JS_HAS_CALL_OBJECT
 
518
 
 
519
JSObject *
 
520
js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
 
521
{
 
522
    JSObject *callobj, *funobj;
 
523
 
 
524
    /* Create a call object for fp only if it lacks one. */
 
525
    JS_ASSERT(fp->fun);
 
526
    callobj = fp->callobj;
 
527
    if (callobj)
 
528
        return callobj;
 
529
    JS_ASSERT(fp->fun);
 
530
 
 
531
    /* The default call parent is its function's parent (static link). */
 
532
    if (!parent) {
 
533
        funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
 
534
        if (funobj)
 
535
            parent = OBJ_GET_PARENT(cx, funobj);
 
536
    }
 
537
 
 
538
    /* Create the call object and link it to its stack frame. */
 
539
    callobj = js_NewObject(cx, &js_CallClass, NULL, parent);
 
540
    if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
 
541
        cx->newborn[GCX_OBJECT] = NULL;
 
542
        return NULL;
 
543
    }
 
544
    fp->callobj = callobj;
 
545
 
 
546
    /* Make callobj be the scope chain and the variables object. */
 
547
    fp->scopeChain = callobj;
 
548
    fp->varobj = callobj;
 
549
    return callobj;
 
550
}
 
551
 
 
552
static JSBool
 
553
call_enumerate(JSContext *cx, JSObject *obj);
 
554
 
 
555
JSBool
 
556
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
 
557
{
 
558
    JSObject *callobj;
 
559
    JSBool ok;
 
560
    jsid argsid;
 
561
    jsval aval;
 
562
 
 
563
    /*
 
564
     * Reuse call_enumerate here to reflect all actual args and vars into the
 
565
     * call object from fp.
 
566
     */
 
567
    callobj = fp->callobj;
 
568
    if (!callobj)
 
569
        return JS_TRUE;
 
570
    ok = call_enumerate(cx, callobj);
 
571
 
 
572
    /*
 
573
     * Get the arguments object to snapshot fp's actual argument values.
 
574
     */
 
575
    if (fp->argsobj) {
 
576
        argsid = (jsid) cx->runtime->atomState.argumentsAtom;
 
577
        ok &= js_GetProperty(cx, callobj, argsid, &aval);
 
578
        ok &= js_SetProperty(cx, callobj, argsid, &aval);
 
579
        ok &= js_PutArgsObject(cx, fp);
 
580
    }
 
581
 
 
582
    /*
 
583
     * Clear the private pointer to fp, which is about to go away (js_Invoke).
 
584
     * Do this last because the call_enumerate and js_GetProperty calls above
 
585
     * need to follow the private slot to find fp.
 
586
     */
 
587
    ok &= JS_SetPrivate(cx, callobj, NULL);
 
588
    fp->callobj = NULL;
 
589
    return ok;
 
590
}
 
591
 
 
592
static JSPropertySpec call_props[] = {
 
593
    {js_arguments_str,  CALL_ARGUMENTS, JSPROP_PERMANENT,0,0},
 
594
    {"__callee__",      CALL_CALLEE,    0,0,0},
 
595
    {0,0,0,0,0}
 
596
};
 
597
 
 
598
static JSBool
 
599
call_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
600
{
 
601
    JSStackFrame *fp;
 
602
    jsint slot;
 
603
 
 
604
    if (!JSVAL_IS_INT(id))
 
605
        return JS_TRUE;
 
606
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
607
    if (!fp)
 
608
        return JS_TRUE;
 
609
    JS_ASSERT(fp->fun);
 
610
 
 
611
    slot = JSVAL_TO_INT(id);
 
612
    switch (slot) {
 
613
      case CALL_ARGUMENTS:
 
614
        if (!TEST_OVERRIDE_BIT(fp, slot)) {
 
615
            JSObject *argsobj = js_GetArgsObject(cx, fp);
 
616
            if (!argsobj)
 
617
                return JS_FALSE;
 
618
            *vp = OBJECT_TO_JSVAL(argsobj);
 
619
        }
 
620
        break;
 
621
 
 
622
      case CALL_CALLEE:
 
623
        if (!TEST_OVERRIDE_BIT(fp, slot))
 
624
            *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
 
625
        break;
 
626
 
 
627
      default:
 
628
        if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
 
629
            *vp = fp->argv[slot];
 
630
        break;
 
631
    }
 
632
    return JS_TRUE;
 
633
}
 
634
 
 
635
static JSBool
 
636
call_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
637
{
 
638
    JSStackFrame *fp;
 
639
    jsint slot;
 
640
 
 
641
    if (!JSVAL_IS_INT(id))
 
642
        return JS_TRUE;
 
643
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
644
    if (!fp)
 
645
        return JS_TRUE;
 
646
    JS_ASSERT(fp->fun);
 
647
 
 
648
    slot = JSVAL_TO_INT(id);
 
649
    switch (slot) {
 
650
      case CALL_ARGUMENTS:
 
651
      case CALL_CALLEE:
 
652
        SET_OVERRIDE_BIT(fp, slot);
 
653
        break;
 
654
 
 
655
      default:
 
656
        if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
 
657
            fp->argv[slot] = *vp;
 
658
        break;
 
659
    }
 
660
    return JS_TRUE;
 
661
}
 
662
 
 
663
JSBool
 
664
js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
665
{
 
666
    JSStackFrame *fp;
 
667
 
 
668
    JS_ASSERT(JSVAL_IS_INT(id));
 
669
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
670
    if (fp) {
 
671
        /* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
 
672
        if ((uintN)JSVAL_TO_INT(id) < fp->nvars)
 
673
            *vp = fp->vars[JSVAL_TO_INT(id)];
 
674
    }
 
675
    return JS_TRUE;
 
676
}
 
677
 
 
678
JSBool
 
679
js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
680
{
 
681
    JSStackFrame *fp;
 
682
 
 
683
    JS_ASSERT(JSVAL_IS_INT(id));
 
684
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
685
    if (fp) {
 
686
        /* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
 
687
        jsint slot = JSVAL_TO_INT(id);
 
688
        if ((uintN)slot < fp->nvars)
 
689
            fp->vars[slot] = *vp;
 
690
    }
 
691
    return JS_TRUE;
 
692
}
 
693
 
 
694
static JSBool
 
695
call_enumerate(JSContext *cx, JSObject *obj)
 
696
{
 
697
    JSStackFrame *fp;
 
698
    JSObject *funobj;
 
699
    JSScope *scope;
 
700
    JSScopeProperty *sprop, *cprop;
 
701
    JSPropertyOp getter;
 
702
    jsval *vec;
 
703
    JSProperty *prop;
 
704
 
 
705
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
706
    if (!fp)
 
707
        return JS_TRUE;
 
708
 
 
709
    /*
 
710
     * Do not enumerate a cloned function object at fp->argv[-2], it may have
 
711
     * gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
 
712
     * the clone's prototype property).  We must enumerate the function object
 
713
     * that was decorated with parameter and local variable properties by the
 
714
     * compiler when the compiler created fp->fun, namely fp->fun->object.
 
715
     *
 
716
     * Contrast with call_resolve, where we prefer fp->argv[-2], because we'll
 
717
     * use js_LookupProperty to find any overridden properties in that object,
 
718
     * if it was a mutated clone; and if not, we will search its prototype,
 
719
     * fp->fun->object, to find compiler-created params and locals.
 
720
     */
 
721
    funobj = fp->fun->object;
 
722
    if (!funobj)
 
723
        return JS_TRUE;
 
724
 
 
725
    /*
 
726
     * Reflect actual args from fp->argv for formal parameters, and local vars
 
727
     * and functions in fp->vars for declared variables and nested-at-top-level
 
728
     * local functions.
 
729
     */
 
730
    scope = OBJ_SCOPE(funobj);
 
731
    for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
 
732
        getter = sprop->getter;
 
733
        if (getter == js_GetArgument)
 
734
            vec = fp->argv;
 
735
        else if (getter == js_GetLocalVariable)
 
736
            vec = fp->vars;
 
737
        else
 
738
            continue;
 
739
 
 
740
        /* Trigger reflection in call_resolve by doing a lookup. */
 
741
        if (!js_LookupProperty(cx, obj, sprop->id, &obj, &prop))
 
742
            return JS_FALSE;
 
743
        JS_ASSERT(obj && prop);
 
744
        cprop = (JSScopeProperty *)prop;
 
745
        LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[sprop->shortid]);
 
746
        OBJ_DROP_PROPERTY(cx, obj, prop);
 
747
    }
 
748
 
 
749
    return JS_TRUE;
 
750
}
 
751
 
 
752
static JSBool
 
753
call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
 
754
             JSObject **objp)
 
755
{
 
756
    JSStackFrame *fp;
 
757
    JSObject *funobj;
 
758
    JSString *str;
 
759
    JSAtom *atom;
 
760
    JSObject *obj2;
 
761
    JSScopeProperty *sprop;
 
762
    jsid propid;
 
763
    JSPropertyOp getter, setter;
 
764
    uintN attrs, slot, nslots, spflags;
 
765
    jsval *vp, value;
 
766
    intN shortid;
 
767
 
 
768
    fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
769
    if (!fp)
 
770
        return JS_TRUE;
 
771
    JS_ASSERT(fp->fun);
 
772
 
 
773
    if (!JSVAL_IS_STRING(id))
 
774
        return JS_TRUE;
 
775
 
 
776
    funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
 
777
    if (!funobj)
 
778
        return JS_TRUE;
 
779
 
 
780
    str = JSVAL_TO_STRING(id);
 
781
    atom = js_AtomizeString(cx, str, 0);
 
782
    if (!atom)
 
783
        return JS_FALSE;
 
784
    if (!js_LookupProperty(cx, funobj, (jsid)atom, &obj2,
 
785
                           (JSProperty **)&sprop)) {
 
786
        return JS_FALSE;
 
787
    }
 
788
 
 
789
    if (sprop && OBJ_IS_NATIVE(obj2)) {
 
790
        propid = sprop->id;
 
791
        getter = sprop->getter;
 
792
        attrs = sprop->attrs & ~JSPROP_SHARED;
 
793
        slot = (uintN) sprop->shortid;
 
794
        OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
 
795
        if (getter == js_GetArgument || getter == js_GetLocalVariable) {
 
796
            if (getter == js_GetArgument) {
 
797
                vp = fp->argv;
 
798
                nslots = JS_MAX(fp->argc, fp->fun->nargs);
 
799
                getter = setter = NULL;
 
800
            } else {
 
801
                vp = fp->vars;
 
802
                nslots = fp->nvars;
 
803
                getter = js_GetCallVariable;
 
804
                setter = js_SetCallVariable;
 
805
            }
 
806
            if (slot < nslots) {
 
807
                value = vp[slot];
 
808
                spflags = SPROP_HAS_SHORTID;
 
809
                shortid = (intN) slot;
 
810
            } else {
 
811
                value = JSVAL_VOID;
 
812
                spflags = 0;
 
813
                shortid = 0;
 
814
            }
 
815
            if (!js_DefineNativeProperty(cx, obj, propid, value,
 
816
                                         getter, setter, attrs,
 
817
                                         spflags, shortid, NULL)) {
 
818
                return JS_FALSE;
 
819
            }
 
820
            *objp = obj;
 
821
        }
 
822
    }
 
823
    return JS_TRUE;
 
824
}
 
825
 
 
826
static JSBool
 
827
call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
 
828
{
 
829
    JSStackFrame *fp;
 
830
 
 
831
    if (type == JSTYPE_FUNCTION) {
 
832
        fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
 
833
        if (fp) {
 
834
            JS_ASSERT(fp->fun);
 
835
            *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
 
836
        }
 
837
    }
 
838
    return JS_TRUE;
 
839
}
 
840
 
 
841
JSClass js_CallClass = {
 
842
    js_Call_str,
 
843
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
 
844
    JS_PropertyStub,  JS_PropertyStub,
 
845
    call_getProperty, call_setProperty,
 
846
    call_enumerate,   (JSResolveOp)call_resolve,
 
847
    call_convert,     JS_FinalizeStub,
 
848
    JSCLASS_NO_OPTIONAL_MEMBERS
 
849
};
 
850
 
 
851
#endif /* JS_HAS_CALL_OBJECT */
 
852
 
 
853
/* SHARED because fun_getProperty always computes a new value. */
 
854
#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
 
855
 
 
856
static JSPropertySpec function_props[] = {
 
857
    {js_arguments_str, CALL_ARGUMENTS, FUNCTION_PROP_ATTRS,0,0},
 
858
    {js_arity_str,     FUN_ARITY,      FUNCTION_PROP_ATTRS,0,0},
 
859
    {js_length_str,    ARGS_LENGTH,    FUNCTION_PROP_ATTRS,0,0},
 
860
    {js_name_str,      FUN_NAME,       FUNCTION_PROP_ATTRS,0,0},
 
861
    {js_caller_str,    FUN_CALLER,     FUNCTION_PROP_ATTRS,0,0},
 
862
    {0,0,0,0,0}
 
863
};
 
864
 
 
865
static JSBool
 
866
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 
867
{
 
868
    jsint slot;
 
869
    JSFunction *fun;
 
870
    JSStackFrame *fp;
 
871
#if defined _MSC_VER &&_MSC_VER <= 800
 
872
    /* MSVC1.5 coredumps */
 
873
    jsval bogus = *vp;
 
874
#endif
 
875
 
 
876
    if (!JSVAL_IS_INT(id))
 
877
        return JS_TRUE;
 
878
    slot = JSVAL_TO_INT(id);
 
879
 
 
880
    /* No valid function object should lack private data, but check anyway. */
 
881
    fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
 
882
    if (!fun)
 
883
        return JS_TRUE;
 
884
 
 
885
    /* Find fun's top-most activation record. */
 
886
    for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
 
887
         fp = fp->down) {
 
888
        continue;
 
889
    }
 
890
 
 
891
    switch (slot) {
 
892
      case CALL_ARGUMENTS:
 
893
#if JS_HAS_ARGS_OBJECT
 
894
        /* Warn if strict about f.arguments or equivalent unqualified uses. */
 
895
        if (!JS_ReportErrorFlagsAndNumber(cx,
 
896
                                          JSREPORT_WARNING | JSREPORT_STRICT,
 
897
                                          js_GetErrorMessage, NULL,
 
898
                                          JSMSG_DEPRECATED_USAGE,
 
899
                                          js_arguments_str)) {
 
900
            return JS_FALSE;
 
901
        }
 
902
        if (fp) {
 
903
            if (!js_GetArgsValue(cx, fp, vp))
 
904
                return JS_FALSE;
 
905
        } else {
 
906
            *vp = JSVAL_NULL;
 
907
        }
 
908
        break;
 
909
#else  /* !JS_HAS_ARGS_OBJECT */
 
910
        *vp = OBJECT_TO_JSVAL(fp ? obj : NULL);
 
911
        break;
 
912
#endif /* !JS_HAS_ARGS_OBJECT */
 
913
 
 
914
      case ARGS_LENGTH:
 
915
        if (!JSVERSION_IS_ECMA(cx->version))
 
916
            *vp = INT_TO_JSVAL((jsint)(fp && fp->fun ? fp->argc : fun->nargs));
 
917
        else
 
918
      case FUN_ARITY:
 
919
            *vp = INT_TO_JSVAL((jsint)fun->nargs);
 
920
        break;
 
921
 
 
922
      case FUN_NAME:
 
923
        *vp = fun->atom
 
924
              ? ATOM_KEY(fun->atom)
 
925
              : STRING_TO_JSVAL(cx->runtime->emptyString);
 
926
        break;
 
927
 
 
928
      case FUN_CALLER:
 
929
        while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down)
 
930
            fp = fp->down;
 
931
        if (fp && fp->down && fp->down->fun && fp->down->argv)
 
932
            *vp = fp->down->argv[-2];
 
933
        else
 
934
            *vp = JSVAL_NULL;
 
935
        if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
 
936
            id = ATOM_KEY(cx->runtime->atomState.callerAtom);
 
937
            if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
 
938
                return JS_FALSE;
 
939
        }
 
940
        break;
 
941
 
 
942
      default:
 
943
        /* XXX fun[0] and fun.arguments[0] are equivalent. */
 
944
        if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
 
945
#if defined _MSC_VER &&_MSC_VER <= 800
 
946
          /* MSVC1.5 coredumps */
 
947
          if (bogus == *vp)
 
948
#endif
 
949
            *vp = fp->argv[slot];
 
950
        break;
 
951
    }
 
952
 
 
953
    return JS_TRUE;
 
954
}
 
955
 
 
956
static JSBool
 
957
fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
 
958
            JSObject **objp)
 
959
{
 
960
    JSFunction *fun;
 
961
    JSString *str;
 
962
    JSAtom *prototypeAtom;
 
963
 
 
964
    if (!JSVAL_IS_STRING(id))
 
965
        return JS_TRUE;
 
966
 
 
967
    /* No valid function object should lack private data, but check anyway. */
 
968
    fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
 
969
    if (!fun || !fun->object)
 
970
        return JS_TRUE;
 
971
 
 
972
    /* No need to reflect fun.prototype in 'fun.prototype = ...'. */
 
973
    if (flags & JSRESOLVE_ASSIGNING)
 
974
        return JS_TRUE;
 
975
 
 
976
    /*
 
977
     * Ok, check whether id is 'prototype' and bootstrap the function object's
 
978
     * prototype property.
 
979
     */
 
980
    str = JSVAL_TO_STRING(id);
 
981
    prototypeAtom = cx->runtime->atomState.classPrototypeAtom;
 
982
    if (str == ATOM_TO_STRING(prototypeAtom)) {
 
983
        JSObject *proto, *parentProto;
 
984
        jsval pval;
 
985
 
 
986
        proto = parentProto = NULL;
 
987
        if (fun->object != obj && fun->object) {
 
988
            /*
 
989
             * Clone of a function: make its prototype property value have the
 
990
             * same class as the clone-parent's prototype.
 
991
             */
 
992
            if (!OBJ_GET_PROPERTY(cx, fun->object, (jsid)prototypeAtom, &pval))
 
993
                return JS_FALSE;
 
994
            if (JSVAL_IS_OBJECT(pval))
 
995
                parentProto = JSVAL_TO_OBJECT(pval);
 
996
        }
 
997
 
 
998
        /*
 
999
         * Beware of the wacky case of a user function named Object -- trying
 
1000
         * to find a prototype for that will recur back here ad perniciem.
 
1001
         */
 
1002
        if (!parentProto && fun->atom == cx->runtime->atomState.ObjectAtom)
 
1003
            return JS_TRUE;
 
1004
 
 
1005
        /*
 
1006
         * If resolving "prototype" in a clone, clone the parent's prototype.
 
1007
         * Pass the constructor's (obj's) parent as the prototype parent, to
 
1008
         * avoid defaulting to parentProto.constructor.__parent__.
 
1009
         */
 
1010
        proto = js_NewObject(cx, &js_ObjectClass, parentProto,
 
1011
                             OBJ_GET_PARENT(cx, obj));
 
1012
        if (!proto)
 
1013
            return JS_FALSE;
 
1014
 
 
1015
        /*
 
1016
         * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
 
1017
         * user-defined functions, but DontEnum | ReadOnly | DontDelete for
 
1018
         * native "system" constructors such as Object or Function.  So lazily
 
1019
         * set the former here in fun_resolve, but eagerly define the latter
 
1020
         * in JS_InitClass, with the right attributes.
 
1021
         */
 
1022
        if (!js_SetClassPrototype(cx, obj, proto,
 
1023
                                  JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
 
1024
            cx->newborn[GCX_OBJECT] = NULL;
 
1025
            return JS_FALSE;
 
1026
        }
 
1027
        *objp = obj;
 
1028
    }
 
1029
 
 
1030
    return JS_TRUE;
 
1031
}
 
1032
 
 
1033
static JSBool
 
1034
fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
 
1035
{
 
1036
    switch (type) {
 
1037
      case JSTYPE_FUNCTION:
 
1038
        *vp = OBJECT_TO_JSVAL(obj);
 
1039
        return JS_TRUE;
 
1040
      default:
 
1041
        return js_TryValueOf(cx, obj, type, vp);
 
1042
    }
 
1043
}
 
1044
 
 
1045
static void
 
1046
fun_finalize(JSContext *cx, JSObject *obj)
 
1047
{
 
1048
    JSFunction *fun;
 
1049
 
 
1050
    /* No valid function object should lack private data, but check anyway. */
 
1051
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
 
1052
    if (!fun)
 
1053
        return;
 
1054
    if (fun->object == obj)
 
1055
        fun->object = NULL;
 
1056
    JS_ATOMIC_DECREMENT(&fun->nrefs);
 
1057
    if (fun->nrefs)
 
1058
        return;
 
1059
    if (fun->script)
 
1060
        js_DestroyScript(cx, fun->script);
 
1061
    JS_free(cx, fun);
 
1062
}
 
1063
 
 
1064
#if JS_HAS_XDR
 
1065
 
 
1066
#include "jsxdrapi.h"
 
1067
 
 
1068
enum {
 
1069
    JSXDR_FUNARG = 1,
 
1070
    JSXDR_FUNVAR = 2,
 
1071
    JSXDR_FUNCONST = 3
 
1072
};
 
1073
 
 
1074
/* XXX store parent and proto, if defined */
 
1075
static JSBool
 
1076
fun_xdrObject(JSXDRState *xdr, JSObject **objp)
 
1077
{
 
1078
    JSContext *cx;
 
1079
    JSFunction *fun;
 
1080
    JSString *atomstr;
 
1081
    char *propname;
 
1082
    JSScopeProperty *sprop;
 
1083
    uint32 userid;              /* NB: holds a signed int-tagged jsval */
 
1084
    JSAtom *atom;
 
1085
    uintN i, n, dupflag;
 
1086
    uint32 type;
 
1087
#ifdef DEBUG
 
1088
    uintN nvars = 0, nargs = 0;
 
1089
#endif
 
1090
 
 
1091
    cx = xdr->cx;
 
1092
    if (xdr->mode == JSXDR_ENCODE) {
 
1093
        /*
 
1094
         * No valid function object should lack private data, but fail soft
 
1095
         * (return true, no error report) in case one does due to API pilot
 
1096
         * or internal error.
 
1097
         */
 
1098
        fun = (JSFunction *) JS_GetPrivate(cx, *objp);
 
1099
        if (!fun)
 
1100
            return JS_TRUE;
 
1101
        atomstr = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
 
1102
    } else {
 
1103
        fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
 
1104
        if (!fun)
 
1105
            return JS_FALSE;
 
1106
        atomstr = NULL;
 
1107
    }
 
1108
 
 
1109
    if (!JS_XDRStringOrNull(xdr, &atomstr) ||
 
1110
        !JS_XDRUint16(xdr, &fun->nargs) ||
 
1111
        !JS_XDRUint16(xdr, &fun->extra) ||
 
1112
        !JS_XDRUint16(xdr, &fun->nvars) ||
 
1113
        !JS_XDRUint8(xdr, &fun->flags)) {
 
1114
        return JS_FALSE;
 
1115
    }
 
1116
 
 
1117
    /* do arguments and local vars */
 
1118
    if (fun->object) {
 
1119
        n = fun->nargs + fun->nvars;
 
1120
        if (xdr->mode == JSXDR_ENCODE) {
 
1121
            JSScope *scope;
 
1122
            JSScopeProperty **spvec, *auto_spvec[8];
 
1123
            void *mark;
 
1124
 
 
1125
            if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) {
 
1126
                spvec = auto_spvec;
 
1127
                mark = NULL;
 
1128
            } else {
 
1129
                mark = JS_ARENA_MARK(&cx->tempPool);
 
1130
                JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool,
 
1131
                                       n * sizeof(JSScopeProperty *));
 
1132
                if (!spvec) {
 
1133
                    JS_ReportOutOfMemory(cx);
 
1134
                    return JS_FALSE;
 
1135
                }
 
1136
            }
 
1137
            scope = OBJ_SCOPE(fun->object);
 
1138
            for (sprop = SCOPE_LAST_PROP(scope); sprop;
 
1139
                 sprop = sprop->parent) {
 
1140
                if (sprop->getter == js_GetArgument) {
 
1141
                    JS_ASSERT(nargs++ <= fun->nargs);
 
1142
                    spvec[sprop->shortid] = sprop;
 
1143
                } else if (sprop->getter == js_GetLocalVariable) {
 
1144
                    JS_ASSERT(nvars++ <= fun->nvars);
 
1145
                    spvec[fun->nargs + sprop->shortid] = sprop;
 
1146
                }
 
1147
            }
 
1148
            for (i = 0; i < n; i++) {
 
1149
                sprop = spvec[i];
 
1150
                JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
 
1151
                type = (i < fun->nargs)
 
1152
                       ? JSXDR_FUNARG
 
1153
                       : (sprop->attrs & JSPROP_READONLY)
 
1154
                       ? JSXDR_FUNCONST
 
1155
                       : JSXDR_FUNVAR;
 
1156
                userid = INT_TO_JSVAL(sprop->shortid);
 
1157
                /* XXX lossy conversion, need new XDR version for ECMAv3 */
 
1158
                propname = JS_GetStringBytes(ATOM_TO_STRING((JSAtom *)sprop->id));
 
1159
                if (!propname ||
 
1160
                    !JS_XDRUint32(xdr, &type) ||
 
1161
                    !JS_XDRUint32(xdr, &userid) ||
 
1162
                    !JS_XDRCString(xdr, &propname)) {
 
1163
                    if (mark)
 
1164
                        JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1165
                    return JS_FALSE;
 
1166
                }
 
1167
            }
 
1168
            if (mark)
 
1169
                JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1170
        } else {
 
1171
            JSPropertyOp getter, setter;
 
1172
 
 
1173
            for (i = n; i != 0; i--) {
 
1174
                uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
 
1175
 
 
1176
                if (!JS_XDRUint32(xdr, &type) ||
 
1177
                    !JS_XDRUint32(xdr, &userid) ||
 
1178
                    !JS_XDRCString(xdr, &propname)) {
 
1179
                    return JS_FALSE;
 
1180
                }
 
1181
                JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
 
1182
                          type == JSXDR_FUNCONST);
 
1183
                if (type == JSXDR_FUNARG) {
 
1184
                    getter = js_GetArgument;
 
1185
                    setter = js_SetArgument;
 
1186
                    JS_ASSERT(nargs++ <= fun->nargs);
 
1187
                } else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) {
 
1188
                    getter = js_GetLocalVariable;
 
1189
                    setter = js_SetLocalVariable;
 
1190
                    if (type == JSXDR_FUNCONST)
 
1191
                        attrs |= JSPROP_READONLY;
 
1192
                    JS_ASSERT(nvars++ <= fun->nvars);
 
1193
                } else {
 
1194
                    getter = NULL;
 
1195
                    setter = NULL;
 
1196
                }
 
1197
                atom = js_Atomize(cx, propname, strlen(propname), 0);
 
1198
                JS_free(cx, propname);
 
1199
                if (!atom)
 
1200
                    return JS_FALSE;
 
1201
 
 
1202
                /* Flag duplicate argument if atom is bound in fun->object. */
 
1203
                dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), (jsid)atom)
 
1204
                          ? SPROP_IS_DUPLICATE
 
1205
                          : 0;
 
1206
 
 
1207
                if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
 
1208
                                          getter, setter, SPROP_INVALID_SLOT,
 
1209
                                          attrs | JSPROP_SHARED,
 
1210
                                          SPROP_HAS_SHORTID | dupflag,
 
1211
                                          JSVAL_TO_INT(userid))) {
 
1212
                    return JS_FALSE;
 
1213
                }
 
1214
            }
 
1215
        }
 
1216
    }
 
1217
 
 
1218
    if (!js_XDRScript(xdr, &fun->script, NULL))
 
1219
        return JS_FALSE;
 
1220
 
 
1221
    if (xdr->mode == JSXDR_DECODE) {
 
1222
        *objp = fun->object;
 
1223
        if (atomstr) {
 
1224
            fun->atom = js_AtomizeString(cx, atomstr, 0);
 
1225
            if (!fun->atom)
 
1226
                return JS_FALSE;
 
1227
 
 
1228
            if (!OBJ_DEFINE_PROPERTY(cx, cx->globalObject,
 
1229
                                     (jsid)fun->atom, OBJECT_TO_JSVAL(*objp),
 
1230
                                     NULL, NULL, JSPROP_ENUMERATE,
 
1231
                                     NULL)) {
 
1232
                return JS_FALSE;
 
1233
            }
 
1234
        }
 
1235
 
 
1236
        js_CallNewScriptHook(cx, fun->script, fun);
 
1237
    }
 
1238
 
 
1239
    return JS_TRUE;
 
1240
}
 
1241
 
 
1242
#else  /* !JS_HAS_XDR */
 
1243
 
 
1244
#define fun_xdrObject NULL
 
1245
 
 
1246
#endif /* !JS_HAS_XDR */
 
1247
 
 
1248
#if JS_HAS_INSTANCEOF
 
1249
 
 
1250
/*
 
1251
 * [[HasInstance]] internal method for Function objects: fetch the .prototype
 
1252
 * property of its 'this' parameter, and walks the prototype chain of v (only
 
1253
 * if v is an object) returning true if .prototype is found.
 
1254
 */
 
1255
static JSBool
 
1256
fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
 
1257
{
 
1258
    jsval pval, cval;
 
1259
    JSString *str;
 
1260
    JSObject *proto, *obj2;
 
1261
    JSFunction *cfun, *ofun;
 
1262
 
 
1263
    if (!OBJ_GET_PROPERTY(cx, obj,
 
1264
                          (jsid)cx->runtime->atomState.classPrototypeAtom,
 
1265
                          &pval)) {
 
1266
        return JS_FALSE;
 
1267
    }
 
1268
 
 
1269
    if (JSVAL_IS_PRIMITIVE(pval)) {
 
1270
        /*
 
1271
         * Throw a runtime error if instanceof is called on a function that
 
1272
         * has a non-object as its .prototype value.
 
1273
         */
 
1274
        str = js_DecompileValueGenerator(cx, -1, OBJECT_TO_JSVAL(obj), NULL);
 
1275
        if (str) {
 
1276
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
1277
                                 JSMSG_BAD_PROTOTYPE, JS_GetStringBytes(str));
 
1278
        }
 
1279
        return JS_FALSE;
 
1280
    }
 
1281
 
 
1282
    proto = JSVAL_TO_OBJECT(pval);
 
1283
    if (!js_IsDelegate(cx, proto, v, bp))
 
1284
        return JS_FALSE;
 
1285
 
 
1286
    if (!*bp && !JSVAL_IS_PRIMITIVE(v) && v != pval) {
 
1287
        /*
 
1288
         * Extension for "brutal sharing" of standard class constructors: if
 
1289
         * a script is compiled using a single, shared set of constructors, in
 
1290
         * particular Function and RegExp, but executed many times using other
 
1291
         * sets of standard constructors, then (/re/ instanceof RegExp), e.g.,
 
1292
         * will be false.
 
1293
         *
 
1294
         * We extend instanceof in this case to look for a matching native or
 
1295
         * script underlying the function object found in the 'constructor'
 
1296
         * property of the object in question (which is JSVAL_TO_OBJECT(v)),
 
1297
         * or found in the 'constructor' property of one of its prototypes.
 
1298
         *
 
1299
         * See also jsexn.c, where the *Error constructors are defined, each
 
1300
         * with its own native function, to satisfy (e instanceof Error) even
 
1301
         * when exceptions cross standard-class sharing boundaries.  Note that
 
1302
         * Error.prototype may not lie on e's __proto__ chain in that case.
 
1303
         */
 
1304
        obj2 = JSVAL_TO_OBJECT(v);
 
1305
        do {
 
1306
            if (!OBJ_GET_PROPERTY(cx, obj2,
 
1307
                                  (jsid)cx->runtime->atomState.constructorAtom,
 
1308
                                  &cval)) {
 
1309
                return JS_FALSE;
 
1310
            }
 
1311
 
 
1312
            if (JSVAL_IS_FUNCTION(cx, cval)) {
 
1313
                cfun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(cval));
 
1314
                ofun = (JSFunction *) JS_GetPrivate(cx, obj);
 
1315
                if (cfun->native == ofun->native &&
 
1316
                    cfun->script == ofun->script) {
 
1317
                    *bp = JS_TRUE;
 
1318
                    break;
 
1319
                }
 
1320
            }
 
1321
        } while ((obj2 = OBJ_GET_PROTO(cx, obj2)) != NULL);
 
1322
    }
 
1323
 
 
1324
    return JS_TRUE;
 
1325
}
 
1326
 
 
1327
#else  /* !JS_HAS_INSTANCEOF */
 
1328
 
 
1329
#define fun_hasInstance NULL
 
1330
 
 
1331
#endif /* !JS_HAS_INSTANCEOF */
 
1332
 
 
1333
static uint32
 
1334
fun_mark(JSContext *cx, JSObject *obj, void *arg)
 
1335
{
 
1336
    JSFunction *fun;
 
1337
 
 
1338
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
 
1339
    if (fun) {
 
1340
        if (fun->atom)
 
1341
            GC_MARK_ATOM(cx, fun->atom, arg);
 
1342
        if (fun->script)
 
1343
            js_MarkScript(cx, fun->script, arg);
 
1344
    }
 
1345
    return 0;
 
1346
}
 
1347
 
 
1348
/*
 
1349
 * Reserve two slots in all function objects for XPConnect.  Note that this
 
1350
 * does not bloat every instance, only those on which reserved slots are set,
 
1351
 * and those on which ad-hoc properties are defined.
 
1352
 */
 
1353
JSClass js_FunctionClass = {
 
1354
    js_Function_str,
 
1355
    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2),
 
1356
    JS_PropertyStub,  JS_PropertyStub,
 
1357
    fun_getProperty,  JS_PropertyStub,
 
1358
    JS_EnumerateStub, (JSResolveOp)fun_resolve,
 
1359
    fun_convert,      fun_finalize,
 
1360
    NULL,             NULL,
 
1361
    NULL,             NULL,
 
1362
    fun_xdrObject,    fun_hasInstance,
 
1363
    fun_mark,         0
 
1364
};
 
1365
 
 
1366
JSBool
 
1367
js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
 
1368
                uintN argc, jsval *argv, jsval *rval)
 
1369
{
 
1370
    jsval fval;
 
1371
    JSFunction *fun;
 
1372
    JSString *str;
 
1373
 
 
1374
    if (!argv) {
 
1375
        JS_ASSERT(JS_ObjectIsFunction(cx, obj));
 
1376
    } else {
 
1377
        fval = argv[-1];
 
1378
        if (!JSVAL_IS_FUNCTION(cx, fval)) {
 
1379
            /*
 
1380
             * If we don't have a function to start off with, try converting
 
1381
             * the object to a function.  If that doesn't work, complain.
 
1382
             */
 
1383
            if (JSVAL_IS_OBJECT(fval)) {
 
1384
                obj = JSVAL_TO_OBJECT(fval);
 
1385
                if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
 
1386
                                                     &fval)) {
 
1387
                    return JS_FALSE;
 
1388
                }
 
1389
            }
 
1390
            if (!JSVAL_IS_FUNCTION(cx, fval)) {
 
1391
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
1392
                                     JSMSG_INCOMPATIBLE_PROTO,
 
1393
                                     js_Function_str, js_toString_str,
 
1394
                                     JS_GetTypeName(cx,
 
1395
                                                    JS_TypeOfValue(cx, fval)));
 
1396
                return JS_FALSE;
 
1397
            }
 
1398
        }
 
1399
 
 
1400
        obj = JSVAL_TO_OBJECT(fval);
 
1401
    }
 
1402
 
 
1403
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
 
1404
    if (!fun)
 
1405
        return JS_TRUE;
 
1406
    if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent))
 
1407
        return JS_FALSE;
 
1408
    str = JS_DecompileFunction(cx, fun, (uintN)indent);
 
1409
    if (!str)
 
1410
        return JS_FALSE;
 
1411
    *rval = STRING_TO_JSVAL(str);
 
1412
    return JS_TRUE;
 
1413
}
 
1414
 
 
1415
static JSBool
 
1416
fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
1417
{
 
1418
    return js_fun_toString(cx, obj, 0, argc, argv, rval);
 
1419
}
 
1420
 
 
1421
#if JS_HAS_TOSOURCE
 
1422
static JSBool
 
1423
fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
1424
{
 
1425
    return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);
 
1426
}
 
1427
#endif
 
1428
 
 
1429
static const char js_call_str[] = "call";
 
1430
 
 
1431
#if JS_HAS_CALL_FUNCTION
 
1432
static JSBool
 
1433
fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
1434
{
 
1435
    jsval fval, *sp, *oldsp;
 
1436
    void *mark;
 
1437
    uintN i;
 
1438
    JSStackFrame *fp;
 
1439
    JSBool ok;
 
1440
 
 
1441
    if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
 
1442
        return JS_FALSE;
 
1443
    fval = argv[-1];
 
1444
 
 
1445
    if (!JSVAL_IS_FUNCTION(cx, fval)) {
 
1446
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
1447
                             JSMSG_INCOMPATIBLE_PROTO,
 
1448
                             js_Function_str, js_call_str,
 
1449
                             JS_GetStringBytes(JS_ValueToString(cx, fval)));
 
1450
        return JS_FALSE;
 
1451
    }
 
1452
 
 
1453
    if (argc == 0) {
 
1454
        /* Call fun with its parent as the 'this' parameter if no args. */
 
1455
        obj = OBJ_GET_PARENT(cx, obj);
 
1456
    } else {
 
1457
        /* Otherwise convert the first arg to 'this' and skip over it. */
 
1458
        if (!js_ValueToObject(cx, argv[0], &obj))
 
1459
            return JS_FALSE;
 
1460
        argc--;
 
1461
        argv++;
 
1462
    }
 
1463
 
 
1464
    /* Allocate stack space for fval, obj, and the args. */
 
1465
    sp = js_AllocStack(cx, 2 + argc, &mark);
 
1466
    if (!sp)
 
1467
        return JS_FALSE;
 
1468
 
 
1469
    /* Push fval, obj, and the args. */
 
1470
    *sp++ = fval;
 
1471
    *sp++ = OBJECT_TO_JSVAL(obj);
 
1472
    for (i = 0; i < argc; i++)
 
1473
        *sp++ = argv[i];
 
1474
 
 
1475
    /* Lift current frame to include the args and do the call. */
 
1476
    fp = cx->fp;
 
1477
    oldsp = fp->sp;
 
1478
    fp->sp = sp;
 
1479
    ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
 
1480
 
 
1481
    /* Store rval and pop stack back to our frame's sp. */
 
1482
    *rval = fp->sp[-1];
 
1483
    fp->sp = oldsp;
 
1484
    js_FreeStack(cx, mark);
 
1485
    return ok;
 
1486
}
 
1487
#endif /* JS_HAS_CALL_FUNCTION */
 
1488
 
 
1489
#if JS_HAS_APPLY_FUNCTION
 
1490
static JSBool
 
1491
fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
1492
{
 
1493
    jsval fval, *sp, *oldsp;
 
1494
    JSObject *aobj;
 
1495
    jsuint length;
 
1496
    void *mark;
 
1497
    uintN i;
 
1498
    JSBool ok;
 
1499
    JSStackFrame *fp;
 
1500
 
 
1501
    if (argc == 0) {
 
1502
        /* Will get globalObject as 'this' and no other arguments. */
 
1503
        return fun_call(cx, obj, argc, argv, rval);
 
1504
    }
 
1505
 
 
1506
    if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
 
1507
        return JS_FALSE;
 
1508
    fval = argv[-1];
 
1509
 
 
1510
    if (!JSVAL_IS_FUNCTION(cx, fval)) {
 
1511
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
1512
                             JSMSG_INCOMPATIBLE_PROTO,
 
1513
                             js_Function_str, "apply",
 
1514
                             JS_GetStringBytes(JS_ValueToString(cx, fval)));
 
1515
        return JS_FALSE;
 
1516
    }
 
1517
 
 
1518
    /* Quell GCC overwarnings. */
 
1519
    aobj = NULL;
 
1520
    length = 0;
 
1521
 
 
1522
    if (argc >= 2) {
 
1523
        /* If the 2nd arg is null or void, call the function with 0 args. */
 
1524
        if (JSVAL_IS_NULL(argv[1]) || JSVAL_IS_VOID(argv[1])) {
 
1525
            argc = 0;
 
1526
        } else {
 
1527
            /* The second arg must be an array (or arguments object). */
 
1528
            if (JSVAL_IS_PRIMITIVE(argv[1]) ||
 
1529
                (aobj = JSVAL_TO_OBJECT(argv[1]),
 
1530
                OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass &&
 
1531
                OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass))
 
1532
            {
 
1533
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
1534
                                     JSMSG_BAD_APPLY_ARGS);
 
1535
                return JS_FALSE;
 
1536
            }
 
1537
            if (!js_GetLengthProperty(cx, aobj, &length))
 
1538
                return JS_FALSE;
 
1539
        }
 
1540
    }
 
1541
 
 
1542
    /* Convert the first arg to 'this' and skip over it. */
 
1543
    if (!js_ValueToObject(cx, argv[0], &obj))
 
1544
        return JS_FALSE;
 
1545
 
 
1546
    /* Allocate stack space for fval, obj, and the args. */
 
1547
    argc = (uintN)JS_MIN(length, ARGC_LIMIT - 1);
 
1548
    sp = js_AllocStack(cx, 2 + argc, &mark);
 
1549
    if (!sp)
 
1550
        return JS_FALSE;
 
1551
 
 
1552
    /* Push fval, obj, and aobj's elements as args. */
 
1553
    *sp++ = fval;
 
1554
    *sp++ = OBJECT_TO_JSVAL(obj);
 
1555
    for (i = 0; i < argc; i++) {
 
1556
        ok = JS_GetElement(cx, aobj, (jsint)i, sp);
 
1557
        if (!ok)
 
1558
            goto out;
 
1559
        sp++;
 
1560
    }
 
1561
 
 
1562
    /* Lift current frame to include the args and do the call. */
 
1563
    fp = cx->fp;
 
1564
    oldsp = fp->sp;
 
1565
    fp->sp = sp;
 
1566
    ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
 
1567
 
 
1568
    /* Store rval and pop stack back to our frame's sp. */
 
1569
    *rval = fp->sp[-1];
 
1570
    fp->sp = oldsp;
 
1571
out:
 
1572
    js_FreeStack(cx, mark);
 
1573
    return ok;
 
1574
}
 
1575
#endif /* JS_HAS_APPLY_FUNCTION */
 
1576
 
 
1577
static JSFunctionSpec function_methods[] = {
 
1578
#if JS_HAS_TOSOURCE
 
1579
    {js_toSource_str,   fun_toSource,   0,0,0},
 
1580
#endif
 
1581
    {js_toString_str,   fun_toString,   1,0,0},
 
1582
#if JS_HAS_APPLY_FUNCTION
 
1583
    {"apply",           fun_apply,      2,0,0},
 
1584
#endif
 
1585
#if JS_HAS_CALL_FUNCTION
 
1586
    {js_call_str,       fun_call,       1,0,0},
 
1587
#endif
 
1588
    {0,0,0,0,0}
 
1589
};
 
1590
 
 
1591
JSBool
 
1592
js_IsIdentifier(JSString *str)
 
1593
{
 
1594
    size_t n;
 
1595
    jschar *s, c;
 
1596
 
 
1597
    n = JSSTRING_LENGTH(str);
 
1598
    if (n == 0)
 
1599
        return JS_FALSE;
 
1600
    s = JSSTRING_CHARS(str);
 
1601
    c = *s;
 
1602
    if (!JS_ISIDENT_START(c))
 
1603
        return JS_FALSE;
 
1604
    for (n--; n != 0; n--) {
 
1605
        c = *++s;
 
1606
        if (!JS_ISIDENT(c))
 
1607
            return JS_FALSE;
 
1608
    }
 
1609
    return JS_TRUE;
 
1610
}
 
1611
 
 
1612
static JSBool
 
1613
Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
1614
{
 
1615
    JSStackFrame *fp, *caller;
 
1616
    JSFunction *fun;
 
1617
    JSObject *parent;
 
1618
    uintN i, n, lineno, dupflag;
 
1619
    JSAtom *atom;
 
1620
    const char *filename;
 
1621
    JSObject *obj2;
 
1622
    JSScopeProperty *sprop;
 
1623
    JSString *str, *arg;
 
1624
    void *mark;
 
1625
    JSTokenStream *ts;
 
1626
    JSPrincipals *principals;
 
1627
    jschar *collected_args, *cp;
 
1628
    size_t arg_length, args_length;
 
1629
    JSTokenType tt;
 
1630
    JSBool ok;
 
1631
 
 
1632
    fp = cx->fp;
 
1633
    if (fp && !(fp->flags & JSFRAME_CONSTRUCTING)) {
 
1634
        obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);
 
1635
        if (!obj)
 
1636
            return JS_FALSE;
 
1637
        *rval = OBJECT_TO_JSVAL(obj);
 
1638
    }
 
1639
    fun = (JSFunction *) JS_GetPrivate(cx, obj);
 
1640
    if (fun)
 
1641
        return JS_TRUE;
 
1642
 
 
1643
#if JS_HAS_CALL_OBJECT
 
1644
    /*
 
1645
     * NB: (new Function) is not lexically closed by its caller, it's just an
 
1646
     * anonymous function in the top-level scope that its constructor inhabits.
 
1647
     * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
 
1648
     * and so would a call to f from another top-level's script or function.
 
1649
     *
 
1650
     * In older versions, before call objects, a new Function was adopted by
 
1651
     * its running context's globalObject, which might be different from the
 
1652
     * top-level reachable from scopeChain (in HTML frames, e.g.).
 
1653
     */
 
1654
    parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
 
1655
#else
 
1656
    /* Set up for dynamic parenting (see js_Invoke in jsinterp.c). */
 
1657
    parent = NULL;
 
1658
#endif
 
1659
 
 
1660
    fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
 
1661
                         JSVERSION_IS_ECMA(cx->version)
 
1662
                         ? cx->runtime->atomState.anonymousAtom
 
1663
                         : NULL);
 
1664
 
 
1665
    if (!fun)
 
1666
        return JS_FALSE;
 
1667
 
 
1668
    /*
 
1669
     * Function is static and not called directly by other functions in this
 
1670
     * file, therefore it is callable only as a native function by js_Invoke.
 
1671
     * Find the scripted caller, possibly skipping other native frames such as
 
1672
     * are built for Function.prototype.call or .apply activations that invoke
 
1673
     * Function indirectly from a script.
 
1674
     */
 
1675
    JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function);
 
1676
    caller = JS_GetScriptedCaller(cx, fp);
 
1677
    if (caller) {
 
1678
        filename = caller->script->filename;
 
1679
        lineno = js_PCToLineNumber(cx, caller->script, caller->pc);
 
1680
        principals = JS_EvalFramePrincipals(cx, fp, caller);
 
1681
    } else {
 
1682
        filename = NULL;
 
1683
        lineno = 0;
 
1684
        principals = NULL;
 
1685
    }
 
1686
 
 
1687
    n = argc ? argc - 1 : 0;
 
1688
    if (n > 0) {
 
1689
        /*
 
1690
         * Collect the function-argument arguments into one string, separated
 
1691
         * by commas, then make a tokenstream from that string, and scan it to
 
1692
         * get the arguments.  We need to throw the full scanner at the
 
1693
         * problem, because the argument string can legitimately contain
 
1694
         * comments and linefeeds.  XXX It might be better to concatenate
 
1695
         * everything up into a function definition and pass it to the
 
1696
         * compiler, but doing it this way is less of a delta from the old
 
1697
         * code.  See ECMA 15.3.2.1.
 
1698
         */
 
1699
        args_length = 0;
 
1700
        for (i = 0; i < n; i++) {
 
1701
            /* Collect the lengths for all the function-argument arguments. */
 
1702
            arg = js_ValueToString(cx, argv[i]);
 
1703
            if (!arg)
 
1704
                return JS_FALSE;
 
1705
            argv[i] = STRING_TO_JSVAL(arg);
 
1706
            args_length += JSSTRING_LENGTH(arg);
 
1707
        }
 
1708
        /* Add 1 for each joining comma. */
 
1709
        args_length += n - 1;
 
1710
 
 
1711
        /*
 
1712
         * Allocate a string to hold the concatenated arguments, including room
 
1713
         * for a terminating 0.  Mark cx->tempPool for later release, to free
 
1714
         * collected_args and its tokenstream in one swoop.
 
1715
         */
 
1716
        mark = JS_ARENA_MARK(&cx->tempPool);
 
1717
        JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
 
1718
                               (args_length+1) * sizeof(jschar));
 
1719
        if (!cp)
 
1720
            return JS_FALSE;
 
1721
        collected_args = cp;
 
1722
 
 
1723
        /*
 
1724
         * Concatenate the arguments into the new string, separated by commas.
 
1725
         */
 
1726
        for (i = 0; i < n; i++) {
 
1727
            arg = JSVAL_TO_STRING(argv[i]);
 
1728
            arg_length = JSSTRING_LENGTH(arg);
 
1729
            (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
 
1730
            cp += arg_length;
 
1731
 
 
1732
            /* Add separating comma or terminating 0. */
 
1733
            *cp++ = (i + 1 < n) ? ',' : 0;
 
1734
        }
 
1735
 
 
1736
        /*
 
1737
         * Make a tokenstream (allocated from cx->tempPool) that reads from
 
1738
         * the given string.
 
1739
         */
 
1740
        ts = js_NewTokenStream(cx, collected_args, args_length, filename,
 
1741
                               lineno, principals);
 
1742
        if (!ts) {
 
1743
            JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1744
            return JS_FALSE;
 
1745
        }
 
1746
 
 
1747
        /* The argument string may be empty or contain no tokens. */
 
1748
        tt = js_GetToken(cx, ts);
 
1749
        if (tt != TOK_EOF) {
 
1750
            for (;;) {
 
1751
                /*
 
1752
                 * Check that it's a name.  This also implicitly guards against
 
1753
                 * TOK_ERROR, which was already reported.
 
1754
                 */
 
1755
                if (tt != TOK_NAME)
 
1756
                    goto bad_formal;
 
1757
 
 
1758
                /*
 
1759
                 * Get the atom corresponding to the name from the tokenstream;
 
1760
                 * we're assured at this point that it's a valid identifier.
 
1761
                 */
 
1762
                atom = CURRENT_TOKEN(ts).t_atom;
 
1763
                if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2,
 
1764
                                       (JSProperty **)&sprop)) {
 
1765
                    goto bad_formal;
 
1766
                }
 
1767
                dupflag = 0;
 
1768
                if (sprop) {
 
1769
                    ok = JS_TRUE;
 
1770
                    if (obj2 == obj) {
 
1771
                        const char *name = js_AtomToPrintableString(cx, atom);
 
1772
 
 
1773
                        /*
 
1774
                         * A duplicate parameter name. We force a duplicate
 
1775
                         * node on the SCOPE_LAST_PROP(scope) list with the
 
1776
                         * same id, distinguished by the SPROP_IS_DUPLICATE
 
1777
                         * flag, and not mapped by an entry in scope.
 
1778
                         */
 
1779
                        JS_ASSERT(sprop->getter == js_GetArgument);
 
1780
                        ok = name &&
 
1781
                             js_ReportCompileErrorNumber(cx, ts, NULL,
 
1782
                                                         JSREPORT_WARNING |
 
1783
                                                         JSREPORT_STRICT,
 
1784
                                                         JSMSG_DUPLICATE_FORMAL,
 
1785
                                                         name);
 
1786
 
 
1787
                        dupflag = SPROP_IS_DUPLICATE;
 
1788
                    }
 
1789
                    OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
 
1790
                    if (!ok)
 
1791
                        goto bad_formal;
 
1792
                    sprop = NULL;
 
1793
                }
 
1794
                if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
 
1795
                                          js_GetArgument, js_SetArgument,
 
1796
                                          SPROP_INVALID_SLOT,
 
1797
                                          JSPROP_ENUMERATE | JSPROP_PERMANENT |
 
1798
                                          JSPROP_SHARED,
 
1799
                                          SPROP_HAS_SHORTID | dupflag,
 
1800
                                          fun->nargs)) {
 
1801
                    goto bad_formal;
 
1802
                }
 
1803
                fun->nargs++;
 
1804
 
 
1805
                /*
 
1806
                 * Get the next token.  Stop on end of stream.  Otherwise
 
1807
                 * insist on a comma, get another name, and iterate.
 
1808
                 */
 
1809
                tt = js_GetToken(cx, ts);
 
1810
                if (tt == TOK_EOF)
 
1811
                    break;
 
1812
                if (tt != TOK_COMMA)
 
1813
                    goto bad_formal;
 
1814
                tt = js_GetToken(cx, ts);
 
1815
            }
 
1816
        }
 
1817
 
 
1818
        /* Clean up. */
 
1819
        ok = js_CloseTokenStream(cx, ts);
 
1820
        JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1821
        if (!ok)
 
1822
            return JS_FALSE;
 
1823
    }
 
1824
 
 
1825
    if (argc) {
 
1826
        str = js_ValueToString(cx, argv[argc-1]);
 
1827
    } else {
 
1828
        /* Can't use cx->runtime->emptyString because we're called too early. */
 
1829
        str = js_NewStringCopyZ(cx, js_empty_ucstr, 0);
 
1830
    }
 
1831
    if (!str)
 
1832
        return JS_FALSE;
 
1833
    if (argv) {
 
1834
        /* Use the last arg (or this if argc == 0) as a local GC root. */
 
1835
        argv[(intN)(argc-1)] = STRING_TO_JSVAL(str);
 
1836
    }
 
1837
 
 
1838
    mark = JS_ARENA_MARK(&cx->tempPool);
 
1839
    ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
 
1840
                           filename, lineno, principals);
 
1841
    if (!ts) {
 
1842
        ok = JS_FALSE;
 
1843
    } else {
 
1844
        ok = js_CompileFunctionBody(cx, ts, fun) &&
 
1845
             js_CloseTokenStream(cx, ts);
 
1846
    }
 
1847
    JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1848
    return ok;
 
1849
 
 
1850
bad_formal:
 
1851
    /*
 
1852
     * Report "malformed formal parameter" iff no illegal char or similar
 
1853
     * scanner error was already reported.
 
1854
     */
 
1855
    if (!(ts->flags & TSF_ERROR))
 
1856
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
 
1857
 
 
1858
    /*
 
1859
     * Clean up the arguments string and tokenstream if we failed to parse
 
1860
     * the arguments.
 
1861
     */
 
1862
    (void)js_CloseTokenStream(cx, ts);
 
1863
    JS_ARENA_RELEASE(&cx->tempPool, mark);
 
1864
    return JS_FALSE;
 
1865
}
 
1866
 
 
1867
JSObject *
 
1868
js_InitFunctionClass(JSContext *cx, JSObject *obj)
 
1869
{
 
1870
    JSObject *proto;
 
1871
    JSAtom *atom;
 
1872
    JSFunction *fun;
 
1873
 
 
1874
    proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
 
1875
                         function_props, function_methods, NULL, NULL);
 
1876
    if (!proto)
 
1877
        return NULL;
 
1878
    atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),
 
1879
                      0);
 
1880
    if (!atom)
 
1881
        goto bad;
 
1882
    fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
 
1883
    if (!fun)
 
1884
        goto bad;
 
1885
    fun->script = js_NewScript(cx, 0, 0, 0);
 
1886
    if (!fun->script)
 
1887
        goto bad;
 
1888
    return proto;
 
1889
 
 
1890
bad:
 
1891
    cx->newborn[GCX_OBJECT] = NULL;
 
1892
    return NULL;
 
1893
}
 
1894
 
 
1895
#if JS_HAS_CALL_OBJECT
 
1896
JSObject *
 
1897
js_InitCallClass(JSContext *cx, JSObject *obj)
 
1898
{
 
1899
    return JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
 
1900
                        call_props, NULL, NULL, NULL);
 
1901
}
 
1902
#endif
 
1903
 
 
1904
JSFunction *
 
1905
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
 
1906
               uintN flags, JSObject *parent, JSAtom *atom)
 
1907
{
 
1908
    JSFunction *fun;
 
1909
 
 
1910
    /* Allocate a function struct. */
 
1911
    fun = (JSFunction *) JS_malloc(cx, sizeof *fun);
 
1912
    if (!fun)
 
1913
        return NULL;
 
1914
 
 
1915
    /* If funobj is null, allocate an object for it. */
 
1916
    if (funobj) {
 
1917
        OBJ_SET_PARENT(cx, funobj, parent);
 
1918
    } else {
 
1919
        funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
 
1920
        if (!funobj) {
 
1921
            JS_free(cx, fun);
 
1922
            return NULL;
 
1923
        }
 
1924
    }
 
1925
 
 
1926
    /* Initialize all function members. */
 
1927
    fun->nrefs = 0;
 
1928
    fun->object = NULL;
 
1929
    fun->native = native;
 
1930
    fun->script = NULL;
 
1931
    fun->nargs = nargs;
 
1932
    fun->extra = 0;
 
1933
    fun->nvars = 0;
 
1934
    fun->flags = flags & JSFUN_FLAGS_MASK;
 
1935
    fun->spare = 0;
 
1936
    fun->atom = atom;
 
1937
    fun->clasp = NULL;
 
1938
 
 
1939
    /* Link fun to funobj and vice versa. */
 
1940
    if (!js_LinkFunctionObject(cx, fun, funobj)) {
 
1941
        cx->newborn[GCX_OBJECT] = NULL;
 
1942
        JS_free(cx, fun);
 
1943
        return NULL;
 
1944
    }
 
1945
    return fun;
 
1946
}
 
1947
 
 
1948
JSObject *
 
1949
js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
 
1950
{
 
1951
    JSObject *newfunobj;
 
1952
    JSFunction *fun;
 
1953
 
 
1954
    JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
 
1955
    newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
 
1956
    if (!newfunobj)
 
1957
        return NULL;
 
1958
    fun = (JSFunction *) JS_GetPrivate(cx, funobj);
 
1959
    if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
 
1960
        cx->newborn[GCX_OBJECT] = NULL;
 
1961
        return NULL;
 
1962
    }
 
1963
    return newfunobj;
 
1964
}
 
1965
 
 
1966
JSBool
 
1967
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
 
1968
{
 
1969
    if (!fun->object)
 
1970
        fun->object = funobj;
 
1971
    if (!JS_SetPrivate(cx, funobj, fun))
 
1972
        return JS_FALSE;
 
1973
    JS_ATOMIC_INCREMENT(&fun->nrefs);
 
1974
    return JS_TRUE;
 
1975
}
 
1976
 
 
1977
JSFunction *
 
1978
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
 
1979
                  uintN nargs, uintN attrs)
 
1980
{
 
1981
    JSFunction *fun;
 
1982
 
 
1983
    fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
 
1984
    if (!fun)
 
1985
        return NULL;
 
1986
    if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(fun->object),
 
1987
                             NULL, NULL, attrs & ~JSFUN_FLAGS_MASK, NULL)) {
 
1988
        return NULL;
 
1989
    }
 
1990
    return fun;
 
1991
}
 
1992
 
 
1993
#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
 
1994
# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
 
1995
#endif
 
1996
 
 
1997
JSFunction *
 
1998
js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
 
1999
{
 
2000
    jsval v;
 
2001
    JSObject *obj;
 
2002
 
 
2003
    v = *vp;
 
2004
    obj = NULL;
 
2005
    if (JSVAL_IS_OBJECT(v)) {
 
2006
        obj = JSVAL_TO_OBJECT(v);
 
2007
        if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
 
2008
            if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
 
2009
                return NULL;
 
2010
            obj = JSVAL_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
 
2011
        }
 
2012
    }
 
2013
    if (!obj) {
 
2014
        js_ReportIsNotFunction(cx, vp, flags);
 
2015
        return NULL;
 
2016
    }
 
2017
    return (JSFunction *) JS_GetPrivate(cx, obj);
 
2018
}
 
2019
 
 
2020
void
 
2021
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
 
2022
{
 
2023
    JSType type;
 
2024
    JSString *fallback;
 
2025
    JSString *str;
 
2026
 
 
2027
    /*
 
2028
     * We provide the typename as the fallback to handle the case when
 
2029
     * valueOf is not a function, which prevents ValueToString from being
 
2030
     * called as the default case inside js_DecompileValueGenerator (and
 
2031
     * so recursing back to here).
 
2032
     */
 
2033
    type = JS_TypeOfValue(cx, *vp);
 
2034
    fallback = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
 
2035
    str = js_DecompileValueGenerator(cx,
 
2036
                                     (flags & JSV2F_SEARCH_STACK)
 
2037
                                     ? JSDVG_SEARCH_STACK
 
2038
                                     : cx->fp
 
2039
                                     ? vp - cx->fp->sp
 
2040
                                     : JSDVG_IGNORE_STACK,
 
2041
                                     *vp,
 
2042
                                     fallback);
 
2043
    if (str) {
 
2044
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
2045
                             (uintN)((flags & JSV2F_CONSTRUCT)
 
2046
                                     ? JSMSG_NOT_CONSTRUCTOR
 
2047
                                     : JSMSG_NOT_FUNCTION),
 
2048
                             JS_GetStringBytes(str));
 
2049
    }
 
2050
}