/[jscoverage]/trunk/js/jsfun.cpp
ViewVC logotype

Annotation of /trunk/js/jsfun.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 399 - (hide annotations)
Tue Dec 9 03:37:47 2008 UTC (10 years, 10 months ago) by siliconforks
File size: 83619 byte(s)
Use SpiderMonkey from Firefox 3.1b2.

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