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

Annotation of /trunk/js/jsfun.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (hide annotations)
Sat Sep 26 23:15:22 2009 UTC (10 years ago) by siliconforks
File size: 98989 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

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 siliconforks 460 static JS_REQUIRES_STACK JSObject *
369     WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunction *fun)
370     {
371     JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
372     JS_ASSERT(fun->optimizedClosure());
373     JS_ASSERT(!fun->u.i.wrapper);
374    
375     /*
376     * We do not attempt to reify Call and Block objects on demand for outer
377     * scopes. This could be done (see the "v8" patch in bug 494235) but it is
378     * fragile in the face of ongoing compile-time optimization. Instead, the
379     * _DBG* opcodes used by wrappers created here must cope with unresolved
380     * upvars and throw them as reference errors. Caveat debuggers!
381     */
382     JSObject *scopeChain = js_GetScopeChain(cx, fp);
383     if (!scopeChain)
384     return NULL;
385    
386     JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass,
387     funobj, scopeChain, 0);
388     if (!wfunobj)
389     return NULL;
390     JSAutoTempValueRooter tvr(cx, wfunobj);
391    
392     JSFunction *wfun = (JSFunction *) wfunobj;
393     wfunobj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(wfun);
394     wfun->nargs = 0;
395     wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
396     wfun->u.i.nvars = 0;
397     wfun->u.i.nupvars = 0;
398     wfun->u.i.skipmin = fun->u.i.skipmin;
399     wfun->u.i.wrapper = true;
400     wfun->u.i.script = NULL;
401     wfun->u.i.names.taggedAtom = NULL;
402     wfun->atom = fun->atom;
403    
404     if (fun->hasLocalNames()) {
405     void *mark = JS_ARENA_MARK(&cx->tempPool);
406     jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
407     if (!names)
408     return NULL;
409    
410     JSBool ok = true;
411     for (uintN i = 0, n = fun->countLocalNames(); i != n; i++) {
412     jsuword name = names[i];
413     JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(name);
414     JSLocalKind localKind = (i < fun->nargs)
415     ? JSLOCAL_ARG
416     : (i < fun->countArgsAndVars())
417     ? (JS_LOCAL_NAME_IS_CONST(name)
418     ? JSLOCAL_CONST
419     : JSLOCAL_VAR)
420     : JSLOCAL_UPVAR;
421    
422     ok = js_AddLocal(cx, wfun, atom, localKind);
423     if (!ok)
424     break;
425     }
426    
427     JS_ARENA_RELEASE(&cx->tempPool, mark);
428     if (!ok)
429     return NULL;
430     JS_ASSERT(wfun->nargs == fun->nargs);
431     JS_ASSERT(wfun->u.i.nvars == fun->u.i.nvars);
432     JS_ASSERT(wfun->u.i.nupvars == fun->u.i.nupvars);
433     js_FreezeLocalNames(cx, wfun);
434     }
435    
436     JSScript *script = fun->u.i.script;
437     jssrcnote *snbase = SCRIPT_NOTES(script);
438     jssrcnote *sn = snbase;
439     while (!SN_IS_TERMINATOR(sn))
440     sn = SN_NEXT(sn);
441     uintN nsrcnotes = (sn - snbase) + 1;
442    
443     /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
444     JSScript *wscript = js_NewScript(cx, script->length, nsrcnotes,
445     script->atomMap.length,
446     (script->objectsOffset != 0)
447     ? JS_SCRIPT_OBJECTS(script)->length
448     : 0,
449     fun->u.i.nupvars,
450     (script->regexpsOffset != 0)
451     ? JS_SCRIPT_REGEXPS(script)->length
452     : 0,
453     (script->trynotesOffset != 0)
454     ? JS_SCRIPT_TRYNOTES(script)->length
455     : 0);
456     if (!wscript)
457     return NULL;
458    
459     memcpy(wscript->code, script->code, script->length);
460     wscript->main = wscript->code + (script->main - script->code);
461    
462     memcpy(SCRIPT_NOTES(wscript), snbase, nsrcnotes);
463     memcpy(wscript->atomMap.vector, script->atomMap.vector,
464     wscript->atomMap.length * sizeof(JSAtom *));
465     if (script->objectsOffset != 0) {
466     memcpy(JS_SCRIPT_OBJECTS(wscript)->vector, JS_SCRIPT_OBJECTS(script)->vector,
467     JS_SCRIPT_OBJECTS(wscript)->length * sizeof(JSObject *));
468     }
469     if (script->regexpsOffset != 0) {
470     memcpy(JS_SCRIPT_REGEXPS(wscript)->vector, JS_SCRIPT_REGEXPS(script)->vector,
471     JS_SCRIPT_REGEXPS(wscript)->length * sizeof(JSObject *));
472     }
473     if (script->trynotesOffset != 0) {
474     memcpy(JS_SCRIPT_TRYNOTES(wscript)->vector, JS_SCRIPT_TRYNOTES(script)->vector,
475     JS_SCRIPT_TRYNOTES(wscript)->length * sizeof(JSTryNote));
476     }
477    
478     if (wfun->u.i.nupvars != 0) {
479     JS_ASSERT(wfun->u.i.nupvars == JS_SCRIPT_UPVARS(wscript)->length);
480     memcpy(JS_SCRIPT_UPVARS(wscript)->vector, JS_SCRIPT_UPVARS(script)->vector,
481     wfun->u.i.nupvars * sizeof(uint32));
482     }
483    
484     jsbytecode *pc = wscript->code;
485     while (*pc != JSOP_STOP) {
486     /* XYZZYbe should copy JSOP_TRAP? */
487     JSOp op = js_GetOpcode(cx, wscript, pc);
488     const JSCodeSpec *cs = &js_CodeSpec[op];
489     ptrdiff_t oplen = cs->length;
490     if (oplen < 0)
491     oplen = js_GetVariableBytecodeLength(pc);
492    
493     /*
494     * Rewrite JSOP_{GET,CALL}DSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
495     * case where fun is an escaping flat closure. This works because the
496     * UPVAR and DSLOT ops by design have the same format: an upvar index
497     * immediate operand.
498     */
499     switch (op) {
500     case JSOP_GETUPVAR: *pc = JSOP_GETUPVAR_DBG; break;
501     case JSOP_CALLUPVAR: *pc = JSOP_CALLUPVAR_DBG; break;
502     case JSOP_GETDSLOT: *pc = JSOP_GETUPVAR_DBG; break;
503     case JSOP_CALLDSLOT: *pc = JSOP_CALLUPVAR_DBG; break;
504     case JSOP_DEFFUN_FC: *pc = JSOP_DEFFUN_DBGFC; break;
505     case JSOP_DEFLOCALFUN_FC: *pc = JSOP_DEFLOCALFUN_DBGFC; break;
506     case JSOP_LAMBDA_FC: *pc = JSOP_LAMBDA_DBGFC; break;
507     default:;
508     }
509     pc += oplen;
510     }
511    
512     /*
513     * Fill in the rest of wscript. This means if you add members to JSScript
514     * you must update this code. FIXME: factor into JSScript::clone method.
515     */
516     wscript->flags = script->flags;
517     wscript->version = script->version;
518     wscript->nfixed = script->nfixed;
519     wscript->filename = script->filename;
520     wscript->lineno = script->lineno;
521     wscript->nslots = script->nslots;
522     wscript->staticLevel = script->staticLevel;
523     wscript->principals = script->principals;
524     if (wscript->principals)
525     JSPRINCIPALS_HOLD(cx, wscript->principals);
526     #ifdef CHECK_SCRIPT_OWNER
527     wscript->owner = script->owner;
528     #endif
529    
530     /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
531     FUN_SET_KIND(wfun, JSFUN_INTERPRETED);
532     wfun->u.i.script = wscript;
533     return wfunobj;
534     }
535    
536 siliconforks 332 static JSBool
537     args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
538     {
539     jsint slot;
540     JSStackFrame *fp;
541    
542     if (!JSVAL_IS_INT(id))
543     return JS_TRUE;
544     fp = (JSStackFrame *)
545     JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
546     if (!fp)
547     return JS_TRUE;
548     JS_ASSERT(fp->argsobj);
549    
550     slot = JSVAL_TO_INT(id);
551     switch (slot) {
552     case ARGS_CALLEE:
553 siliconforks 460 if (!TEST_OVERRIDE_BIT(fp, slot)) {
554     /*
555     * If this function or one in it needs upvars that reach above it
556     * in the scope chain, it must not be a null closure (it could be a
557     * flat closure, or an unoptimized closure -- the latter itself not
558     * necessarily heavyweight). Rather than wrap here, we simply throw
559     * to reduce code size and tell debugger users the truth instead of
560     * passing off a fibbing wrapper.
561     */
562     if (fp->fun->needsWrapper()) {
563     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
564     JSMSG_OPTIMIZED_CLOSURE_LEAK);
565     return JS_FALSE;
566     }
567 siliconforks 332 *vp = OBJECT_TO_JSVAL(fp->callee);
568 siliconforks 460 }
569 siliconforks 332 break;
570    
571     case ARGS_LENGTH:
572     if (!TEST_OVERRIDE_BIT(fp, slot))
573     *vp = INT_TO_JSVAL((jsint)fp->argc);
574     break;
575    
576     default:
577     if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot))
578     *vp = fp->argv[slot];
579     break;
580     }
581     return JS_TRUE;
582     }
583    
584     static JSBool
585     args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
586     {
587     JSStackFrame *fp;
588     jsint slot;
589    
590     if (!JSVAL_IS_INT(id))
591     return JS_TRUE;
592     fp = (JSStackFrame *)
593     JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
594     if (!fp)
595     return JS_TRUE;
596     JS_ASSERT(fp->argsobj);
597    
598     slot = JSVAL_TO_INT(id);
599     switch (slot) {
600     case ARGS_CALLEE:
601     case ARGS_LENGTH:
602     SET_OVERRIDE_BIT(fp, slot);
603     break;
604    
605     default:
606     if (FUN_INTERPRETED(fp->fun) &&
607     (uintN)slot < fp->argc &&
608     !ArgWasDeleted(cx, fp, slot)) {
609     fp->argv[slot] = *vp;
610     }
611     break;
612     }
613     return JS_TRUE;
614     }
615    
616     static JSBool
617     args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
618     JSObject **objp)
619     {
620     JSStackFrame *fp;
621     uintN slot;
622     JSString *str;
623     JSAtom *atom;
624     intN tinyid;
625     jsval value;
626    
627     *objp = NULL;
628     fp = (JSStackFrame *)
629     JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
630     if (!fp)
631     return JS_TRUE;
632     JS_ASSERT(fp->argsobj);
633    
634     if (JSVAL_IS_INT(id)) {
635     slot = JSVAL_TO_INT(id);
636     if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) {
637     /* XXX ECMA specs DontEnum, contrary to other array-like objects */
638     if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id),
639     fp->argv[slot],
640     args_getProperty, args_setProperty,
641     0, NULL)) {
642     return JS_FALSE;
643     }
644     *objp = obj;
645     }
646 siliconforks 460 } else if (JSVAL_IS_STRING(id)) {
647 siliconforks 332 str = JSVAL_TO_STRING(id);
648     atom = cx->runtime->atomState.lengthAtom;
649     if (str == ATOM_TO_STRING(atom)) {
650     tinyid = ARGS_LENGTH;
651     value = INT_TO_JSVAL(fp->argc);
652     } else {
653     atom = cx->runtime->atomState.calleeAtom;
654     if (str == ATOM_TO_STRING(atom)) {
655     tinyid = ARGS_CALLEE;
656     value = OBJECT_TO_JSVAL(fp->callee);
657     } else {
658     atom = NULL;
659    
660     /* Quell GCC overwarnings. */
661     tinyid = 0;
662     value = JSVAL_NULL;
663     }
664     }
665    
666     if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
667     if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
668     args_getProperty, args_setProperty, 0,
669     SPROP_HAS_SHORTID, tinyid, NULL)) {
670     return JS_FALSE;
671     }
672     *objp = obj;
673     }
674     }
675    
676     return JS_TRUE;
677     }
678    
679     static JSBool
680     args_enumerate(JSContext *cx, JSObject *obj)
681     {
682     JSStackFrame *fp;
683     JSObject *pobj;
684     JSProperty *prop;
685     uintN slot, argc;
686    
687     fp = (JSStackFrame *)
688     JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
689     if (!fp)
690     return JS_TRUE;
691     JS_ASSERT(fp->argsobj);
692    
693     /*
694     * Trigger reflection with value snapshot in args_resolve using a series
695     * of js_LookupProperty calls. We handle length, callee, and the indexed
696     * argument properties. We know that args_resolve covers all these cases
697     * and creates direct properties of obj, but that it may fail to resolve
698     * length or callee if overridden.
699     */
700     if (!js_LookupProperty(cx, obj,
701     ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
702     &pobj, &prop)) {
703     return JS_FALSE;
704     }
705     if (prop)
706     OBJ_DROP_PROPERTY(cx, pobj, prop);
707    
708     if (!js_LookupProperty(cx, obj,
709     ATOM_TO_JSID(cx->runtime->atomState.calleeAtom),
710     &pobj, &prop)) {
711     return JS_FALSE;
712     }
713     if (prop)
714     OBJ_DROP_PROPERTY(cx, pobj, prop);
715    
716     argc = fp->argc;
717     for (slot = 0; slot < argc; slot++) {
718     if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop))
719     return JS_FALSE;
720     if (prop)
721     OBJ_DROP_PROPERTY(cx, pobj, prop);
722     }
723     return JS_TRUE;
724     }
725    
726     #if JS_HAS_GENERATORS
727     /*
728     * If a generator-iterator's arguments or call object escapes, it needs to
729     * mark its generator object.
730     */
731     static void
732     args_or_call_trace(JSTracer *trc, JSObject *obj)
733     {
734     JSStackFrame *fp;
735    
736     fp = (JSStackFrame *) JS_GetPrivate(trc->context, obj);
737     if (fp && (fp->flags & JSFRAME_GENERATOR)) {
738     JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj,
739     "FRAME_TO_GENERATOR(fp)->obj");
740     }
741     }
742     #else
743     # define args_or_call_trace NULL
744     #endif
745    
746     /*
747     * The Arguments class is not initialized via JS_InitClass, and must not be,
748     * because its name is "Object". Per ECMA, that causes instances of it to
749     * delegate to the object named by Object.prototype. It also ensures that
750     * arguments.toString() returns "[object Object]".
751     *
752     * The JSClass functions below collaborate to lazily reflect and synchronize
753     * actual argument values, argument count, and callee function object stored
754     * in a JSStackFrame with their corresponding property values in the frame's
755     * arguments object.
756     */
757     JSClass js_ArgumentsClass = {
758     js_Object_str,
759     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
760     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
761     JS_PropertyStub, args_delProperty,
762     args_getProperty, args_setProperty,
763     args_enumerate, (JSResolveOp) args_resolve,
764     JS_ConvertStub, JS_FinalizeStub,
765     NULL, NULL,
766     NULL, NULL,
767     NULL, NULL,
768     JS_CLASS_TRACE(args_or_call_trace), NULL
769     };
770    
771 siliconforks 460 #define JSSLOT_CALLEE (JSSLOT_PRIVATE + 1)
772 siliconforks 332 #define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2)
773     #define CALL_CLASS_FIXED_RESERVED_SLOTS 2
774    
775 siliconforks 460 /*
776     * A Declarative Environment object stores its active JSStackFrame pointer in
777     * its private slot, just as Call and Arguments objects do.
778     */
779     JSClass js_DeclEnvClass = {
780     js_Object_str,
781     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
782     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
783     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
784     JSCLASS_NO_OPTIONAL_MEMBERS
785     };
786    
787     static JS_REQUIRES_STACK JSBool
788     CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp)
789     {
790     JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass ||
791     STOBJ_GET_CLASS(obj) == &js_DeclEnvClass);
792    
793     jsval v = *vp;
794    
795     if (VALUE_IS_FUNCTION(cx, v)) {
796     JSObject *funobj = JSVAL_TO_OBJECT(v);
797     JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
798    
799     /*
800     * Any escaping null or flat closure that reaches above itself or
801     * contains nested functions that reach above it must be wrapped.
802     * We can wrap only when this Call or Declarative Environment obj
803     * still has an active stack frame associated with it.
804     */
805     if (fun->needsWrapper()) {
806     JSStackFrame *fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
807     if (fp) {
808     JSObject *wrapper = WrapEscapingClosure(cx, fp, funobj, fun);
809     if (!wrapper)
810     return false;
811     *vp = OBJECT_TO_JSVAL(wrapper);
812     return true;
813     }
814    
815     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
816     JSMSG_OPTIMIZED_CLOSURE_LEAK);
817     return false;
818     }
819     }
820     return true;
821     }
822    
823     static JS_REQUIRES_STACK JSBool
824     CalleeGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
825     {
826     return CheckForEscapingClosure(cx, obj, vp);
827     }
828    
829 siliconforks 332 JSObject *
830 siliconforks 460 js_GetCallObject(JSContext *cx, JSStackFrame *fp)
831 siliconforks 332 {
832 siliconforks 460 JSObject *callobj;
833 siliconforks 332
834     /* Create a call object for fp only if it lacks one. */
835     JS_ASSERT(fp->fun);
836     callobj = fp->callobj;
837     if (callobj)
838     return callobj;
839    
840 siliconforks 460 #ifdef DEBUG
841     /* A call object should be a frame's outermost scope chain element. */
842     JSClass *classp = OBJ_GET_CLASS(cx, fp->scopeChain);
843     if (classp == &js_WithClass || classp == &js_BlockClass || classp == &js_CallClass)
844     JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp);
845     #endif
846    
847     /*
848     * Create the call object, using the frame's enclosing scope as its
849     * parent, and link the call to its stack frame. For a named function
850     * expression Call's parent points to an environment object holding
851     * function's name.
852     */
853     JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
854     if (lambdaName) {
855     JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
856     fp->scopeChain, 0);
857     if (!env)
858     return NULL;
859     env->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fp);
860    
861     /* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */
862     fp->scopeChain = env;
863     if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName),
864     OBJECT_TO_JSVAL(fp->callee),
865     CalleeGetter, NULL,
866     JSPROP_PERMANENT | JSPROP_READONLY,
867     0, 0, NULL)) {
868     return NULL;
869     }
870 siliconforks 332 }
871    
872 siliconforks 460 callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL,
873     fp->scopeChain, 0);
874 siliconforks 332 if (!callobj)
875     return NULL;
876    
877     JS_SetPrivate(cx, callobj, fp);
878 siliconforks 460 JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee));
879     STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(fp->callee));
880 siliconforks 332 fp->callobj = callobj;
881    
882 siliconforks 460 /*
883     * Push callobj on the top of the scope chain, and make it the
884     * variables object.
885     */
886 siliconforks 332 fp->scopeChain = callobj;
887     fp->varobj = callobj;
888     return callobj;
889     }
890    
891 siliconforks 460 static JSFunction *
892     GetCallObjectFunction(JSObject *obj)
893 siliconforks 332 {
894     jsval v;
895    
896     JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
897 siliconforks 460 v = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
898 siliconforks 332 if (JSVAL_IS_VOID(v)) {
899     /* Newborn or prototype object. */
900     return NULL;
901     }
902     JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
903 siliconforks 460 return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v));
904 siliconforks 332 }
905    
906     JS_FRIEND_API(JSBool)
907     js_PutCallObject(JSContext *cx, JSStackFrame *fp)
908     {
909     JSObject *callobj;
910     JSBool ok;
911     JSFunction *fun;
912     uintN n;
913     JSScope *scope;
914    
915     /*
916     * Since for a call object all fixed slots happen to be taken, we can copy
917     * arguments and variables straight into JSObject.dslots.
918     */
919     JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
920     1 + CALL_CLASS_FIXED_RESERVED_SLOTS);
921    
922     callobj = fp->callobj;
923     if (!callobj)
924     return JS_TRUE;
925    
926     /*
927     * Get the arguments object to snapshot fp's actual argument values.
928     */
929     ok = JS_TRUE;
930     if (fp->argsobj) {
931     if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
932     STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS,
933     OBJECT_TO_JSVAL(fp->argsobj));
934     }
935     ok &= js_PutArgsObject(cx, fp);
936     }
937    
938     fun = fp->fun;
939 siliconforks 460 JS_ASSERT(fun == GetCallObjectFunction(callobj));
940     n = fun->countArgsAndVars();
941 siliconforks 332 if (n != 0) {
942     JS_LOCK_OBJ(cx, callobj);
943     n += JS_INITIAL_NSLOTS;
944     if (n > STOBJ_NSLOTS(callobj))
945     ok &= js_ReallocSlots(cx, callobj, n, JS_TRUE);
946     scope = OBJ_SCOPE(callobj);
947     if (ok) {
948     memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
949     memcpy(callobj->dslots + fun->nargs, fp->slots,
950     fun->u.i.nvars * sizeof(jsval));
951 siliconforks 460 if (scope->object == callobj && n > scope->freeslot)
952     scope->freeslot = n;
953 siliconforks 332 }
954     JS_UNLOCK_SCOPE(cx, scope);
955     }
956    
957     /*
958 siliconforks 460 * Clear private pointers to fp, which is about to go away (js_Invoke).
959 siliconforks 332 * Do this last because js_GetProperty calls above need to follow the
960 siliconforks 460 * call object's private slot to find fp.
961 siliconforks 332 */
962 siliconforks 460 if ((fun->flags & JSFUN_LAMBDA) && fun->atom) {
963     JSObject *env = STOBJ_GET_PARENT(callobj);
964    
965     JS_ASSERT(STOBJ_GET_CLASS(env) == &js_DeclEnvClass);
966     JS_ASSERT(STOBJ_GET_PRIVATE(env) == fp);
967     JS_SetPrivate(cx, env, NULL);
968     }
969    
970 siliconforks 332 JS_SetPrivate(cx, callobj, NULL);
971     fp->callobj = NULL;
972     return ok;
973     }
974    
975     static JSBool
976     call_enumerate(JSContext *cx, JSObject *obj)
977     {
978     JSFunction *fun;
979     uintN n, i;
980     void *mark;
981     jsuword *names;
982     JSBool ok;
983     JSAtom *name;
984     JSObject *pobj;
985     JSProperty *prop;
986    
987 siliconforks 460 fun = GetCallObjectFunction(obj);
988     n = fun ? fun->countArgsAndVars() : 0;
989 siliconforks 332 if (n == 0)
990     return JS_TRUE;
991    
992     mark = JS_ARENA_MARK(&cx->tempPool);
993    
994     MUST_FLOW_THROUGH("out");
995     names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
996     if (!names) {
997     ok = JS_FALSE;
998     goto out;
999     }
1000    
1001     for (i = 0; i != n; ++i) {
1002     name = JS_LOCAL_NAME_TO_ATOM(names[i]);
1003     if (!name)
1004     continue;
1005    
1006     /*
1007     * Trigger reflection by looking up the name of the argument or
1008     * variable.
1009     */
1010     ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(name), &pobj, &prop);
1011     if (!ok)
1012     goto out;
1013    
1014     /*
1015 siliconforks 460 * The call object will always have a property corresponding to the
1016     * argument or variable name because call_resolve creates the property
1017     * using JSPROP_PERMANENT.
1018 siliconforks 332 */
1019 siliconforks 460 JS_ASSERT(prop);
1020     JS_ASSERT(pobj == obj);
1021 siliconforks 332 OBJ_DROP_PROPERTY(cx, pobj, prop);
1022     }
1023     ok = JS_TRUE;
1024    
1025     out:
1026     JS_ARENA_RELEASE(&cx->tempPool, mark);
1027     return ok;
1028     }
1029    
1030     typedef enum JSCallPropertyKind {
1031     JSCPK_ARGUMENTS,
1032     JSCPK_ARG,
1033     JSCPK_VAR
1034     } JSCallPropertyKind;
1035    
1036     static JSBool
1037     CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
1038     JSCallPropertyKind kind, JSBool setter)
1039     {
1040     JSFunction *fun;
1041     JSStackFrame *fp;
1042     uintN i;
1043     jsval *array;
1044    
1045     if (STOBJ_GET_CLASS(obj) != &js_CallClass)
1046     return JS_TRUE;
1047    
1048 siliconforks 460 fun = GetCallObjectFunction(obj);
1049 siliconforks 332 fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
1050    
1051     if (kind == JSCPK_ARGUMENTS) {
1052     if (setter) {
1053     if (fp)
1054     SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS);
1055     STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp);
1056     } else {
1057     if (fp && !TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
1058     JSObject *argsobj;
1059    
1060     argsobj = js_GetArgsObject(cx, fp);
1061     if (!argsobj)
1062     return JS_FALSE;
1063     *vp = OBJECT_TO_JSVAL(argsobj);
1064     } else {
1065     *vp = STOBJ_GET_SLOT(obj, JSSLOT_CALL_ARGUMENTS);
1066     }
1067     }
1068     return JS_TRUE;
1069     }
1070    
1071     JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id));
1072     i = (uint16) JSVAL_TO_INT(id);
1073     JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
1074     JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
1075    
1076     if (!fp) {
1077     i += CALL_CLASS_FIXED_RESERVED_SLOTS;
1078     if (kind == JSCPK_VAR)
1079     i += fun->nargs;
1080     else
1081     JS_ASSERT(kind == JSCPK_ARG);
1082     return setter
1083     ? JS_SetReservedSlot(cx, obj, i, *vp)
1084     : JS_GetReservedSlot(cx, obj, i, vp);
1085     }
1086    
1087     if (kind == JSCPK_ARG) {
1088     array = fp->argv;
1089     } else {
1090     JS_ASSERT(kind == JSCPK_VAR);
1091     array = fp->slots;
1092     }
1093 siliconforks 460 if (setter) {
1094     GC_POKE(cx, array[i]);
1095 siliconforks 332 array[i] = *vp;
1096 siliconforks 460 } else {
1097 siliconforks 332 *vp = array[i];
1098 siliconforks 460 }
1099 siliconforks 332 return JS_TRUE;
1100     }
1101    
1102     static JSBool
1103     GetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1104     {
1105     return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_FALSE);
1106     }
1107    
1108     static JSBool
1109     SetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1110     {
1111     return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_TRUE);
1112     }
1113    
1114     JSBool
1115     js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1116     {
1117     return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_FALSE);
1118     }
1119    
1120     static JSBool
1121     SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1122     {
1123     return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_TRUE);
1124     }
1125    
1126     JSBool
1127     js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1128     {
1129     return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE);
1130     }
1131    
1132 siliconforks 460 JSBool
1133     js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1134     {
1135     if (!CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE))
1136     return JS_FALSE;
1137    
1138     return CheckForEscapingClosure(cx, obj, vp);
1139     }
1140    
1141 siliconforks 332 static JSBool
1142     SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1143     {
1144     return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE);
1145     }
1146    
1147     static JSBool
1148     call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
1149     JSObject **objp)
1150     {
1151 siliconforks 460 jsval callee;
1152 siliconforks 332 JSFunction *fun;
1153     jsid id;
1154     JSLocalKind localKind;
1155     JSPropertyOp getter, setter;
1156     uintN slot, attrs;
1157    
1158 siliconforks 460 JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
1159     JS_ASSERT(!STOBJ_GET_PROTO(obj));
1160    
1161 siliconforks 332 if (!JSVAL_IS_STRING(idval))
1162     return JS_TRUE;
1163    
1164 siliconforks 460 callee = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
1165     if (JSVAL_IS_VOID(callee))
1166 siliconforks 332 return JS_TRUE;
1167 siliconforks 460 fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
1168 siliconforks 332
1169     if (!js_ValueToStringId(cx, idval, &id))
1170     return JS_FALSE;
1171    
1172 siliconforks 460 /*
1173     * Check whether the id refers to a formal parameter, local variable or
1174     * the arguments special name.
1175     *
1176     * We define all such names using JSDNP_DONT_PURGE to avoid an expensive
1177     * shape invalidation in js_DefineNativeProperty. If such an id happens to
1178     * shadow a global or upvar of the same name, any inner functions can
1179     * never access the outer binding. Thus it cannot invalidate any property
1180     * cache entries or derived trace guards for the outer binding. See also
1181     * comments in js_PurgeScopeChainHelper from jsobj.cpp.
1182     */
1183 siliconforks 332 localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
1184 siliconforks 460 if (localKind != JSLOCAL_NONE && localKind != JSLOCAL_UPVAR) {
1185 siliconforks 332 JS_ASSERT((uint16) slot == slot);
1186 siliconforks 460
1187     /*
1188     * We follow 10.2.3 of ECMA 262 v3 and make argument and variable
1189     * properties of the Call objects enumerable.
1190     */
1191     attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
1192 siliconforks 332 if (localKind == JSLOCAL_ARG) {
1193     JS_ASSERT(slot < fun->nargs);
1194     getter = js_GetCallArg;
1195     setter = SetCallArg;
1196     } else {
1197     JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
1198     JS_ASSERT(slot < fun->u.i.nvars);
1199     getter = js_GetCallVar;
1200     setter = SetCallVar;
1201     if (localKind == JSLOCAL_CONST)
1202     attrs |= JSPROP_READONLY;
1203 siliconforks 460
1204     /*
1205     * Use js_GetCallVarChecked if the local's value is a null closure.
1206     * This way we penalize performance only slightly on first use of a
1207     * null closure, not on every use.
1208     */
1209     jsval v;
1210     if (!CallPropertyOp(cx, obj, INT_TO_JSID((int16)slot), &v, JSCPK_VAR, JS_FALSE))
1211     return JS_FALSE;
1212     if (VALUE_IS_FUNCTION(cx, v) &&
1213     GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))->needsWrapper()) {
1214     getter = js_GetCallVarChecked;
1215     }
1216 siliconforks 332 }
1217     if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,
1218     attrs, SPROP_HAS_SHORTID, (int16) slot,
1219 siliconforks 460 NULL, JSDNP_DONT_PURGE)) {
1220 siliconforks 332 return JS_FALSE;
1221     }
1222     *objp = obj;
1223     return JS_TRUE;
1224     }
1225    
1226     /*
1227     * Resolve arguments so that we never store a particular Call object's
1228     * arguments object reference in a Call prototype's |arguments| slot.
1229     */
1230     if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
1231     if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
1232     GetCallArguments, SetCallArguments,
1233     JSPROP_PERMANENT | JSPROP_SHARED,
1234 siliconforks 460 0, 0, NULL, JSDNP_DONT_PURGE)) {
1235 siliconforks 332 return JS_FALSE;
1236     }
1237     *objp = obj;
1238     return JS_TRUE;
1239     }
1240 siliconforks 460
1241     /* Control flow reaches here only if id was not resolved. */
1242 siliconforks 332 return JS_TRUE;
1243     }
1244    
1245     static JSBool
1246     call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1247     {
1248     JSStackFrame *fp;
1249    
1250     if (type == JSTYPE_FUNCTION) {
1251     fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
1252     if (fp) {
1253     JS_ASSERT(fp->fun);
1254     *vp = OBJECT_TO_JSVAL(fp->callee);
1255     }
1256     }
1257     return JS_TRUE;
1258     }
1259    
1260     static uint32
1261     call_reserveSlots(JSContext *cx, JSObject *obj)
1262     {
1263     JSFunction *fun;
1264    
1265 siliconforks 460 fun = GetCallObjectFunction(obj);
1266     return fun->countArgsAndVars();
1267 siliconforks 332 }
1268    
1269     JS_FRIEND_DATA(JSClass) js_CallClass = {
1270 siliconforks 460 "Call",
1271 siliconforks 332 JSCLASS_HAS_PRIVATE |
1272     JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |
1273 siliconforks 460 JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
1274 siliconforks 332 JS_PropertyStub, JS_PropertyStub,
1275     JS_PropertyStub, JS_PropertyStub,
1276     call_enumerate, (JSResolveOp)call_resolve,
1277     call_convert, JS_FinalizeStub,
1278     NULL, NULL,
1279     NULL, NULL,
1280     NULL, NULL,
1281     JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots
1282     };
1283    
1284     static JSBool
1285     fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
1286     {
1287     jsint slot;
1288     JSFunction *fun;
1289     JSStackFrame *fp;
1290     JSSecurityCallbacks *callbacks;
1291    
1292     if (!JSVAL_IS_INT(id))
1293     return JS_TRUE;
1294     slot = JSVAL_TO_INT(id);
1295    
1296     /*
1297     * Loop because getter and setter can be delegated from another class,
1298     * but loop only for ARGS_LENGTH because we must pretend that f.length
1299     * is in each function instance f, per ECMA-262, instead of only in the
1300     * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1301     * to make it appear so).
1302     *
1303     * This code couples tightly to the attributes for the function_props[]
1304     * initializers above, and to js_SetProperty and js_HasOwnProperty.
1305     *
1306     * It's important to allow delegating objects, even though they inherit
1307     * this getter (fun_getProperty), to override arguments, arity, caller,
1308     * and name. If we didn't return early for slot != ARGS_LENGTH, we would
1309     * clobber *vp with the native property value, instead of letting script
1310     * override that value in delegating objects.
1311     *
1312     * Note how that clobbering is what simulates JSPROP_READONLY for all of
1313     * the non-standard properties when the directly addressed object (obj)
1314     * is a function object (i.e., when this loop does not iterate).
1315     */
1316     while (!(fun = (JSFunction *)
1317     JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
1318     if (slot != ARGS_LENGTH)
1319     return JS_TRUE;
1320     obj = OBJ_GET_PROTO(cx, obj);
1321     if (!obj)
1322     return JS_TRUE;
1323     }
1324    
1325     /* Find fun's top-most activation record. */
1326 siliconforks 460 for (fp = js_GetTopStackFrame(cx);
1327     fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
1328 siliconforks 332 fp = fp->down) {
1329     continue;
1330     }
1331    
1332     switch (slot) {
1333     case CALL_ARGUMENTS:
1334     /* Warn if strict about f.arguments or equivalent unqualified uses. */
1335     if (!JS_ReportErrorFlagsAndNumber(cx,
1336     JSREPORT_WARNING | JSREPORT_STRICT,
1337     js_GetErrorMessage, NULL,
1338     JSMSG_DEPRECATED_USAGE,
1339     js_arguments_str)) {
1340     return JS_FALSE;
1341     }
1342     if (fp) {
1343     if (!js_GetArgsValue(cx, fp, vp))
1344     return JS_FALSE;
1345     } else {
1346     *vp = JSVAL_NULL;
1347     }
1348     break;
1349    
1350     case ARGS_LENGTH:
1351     case FUN_ARITY:
1352     *vp = INT_TO_JSVAL((jsint)fun->nargs);
1353     break;
1354    
1355     case FUN_NAME:
1356     *vp = fun->atom
1357     ? ATOM_KEY(fun->atom)
1358     : STRING_TO_JSVAL(cx->runtime->emptyString);
1359     break;
1360    
1361     case FUN_CALLER:
1362 siliconforks 460 if (fp && fp->down && fp->down->fun) {
1363     JSFunction *caller = fp->down->fun;
1364     /*
1365     * See equivalent condition in args_getProperty for ARGS_CALLEE,
1366     * but here we do not want to throw, since this escape can happen
1367     * via foo.caller alone, without any debugger or indirect eval. And
1368     * it seems foo.caller is still used on the Web.
1369     */
1370     if (caller->needsWrapper()) {
1371     JSObject *wrapper = WrapEscapingClosure(cx, fp->down, FUN_OBJECT(caller), caller);
1372     if (!wrapper)
1373     return JS_FALSE;
1374     *vp = OBJECT_TO_JSVAL(wrapper);
1375     return JS_TRUE;
1376     }
1377    
1378 siliconforks 332 *vp = OBJECT_TO_JSVAL(fp->down->callee);
1379 siliconforks 460 } else {
1380 siliconforks 332 *vp = JSVAL_NULL;
1381 siliconforks 460 }
1382 siliconforks 332 if (!JSVAL_IS_PRIMITIVE(*vp)) {
1383     callbacks = JS_GetSecurityCallbacks(cx);
1384     if (callbacks && callbacks->checkObjectAccess) {
1385     id = ATOM_KEY(cx->runtime->atomState.callerAtom);
1386     if (!callbacks->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
1387     return JS_FALSE;
1388     }
1389     }
1390     break;
1391    
1392     default:
1393     /* XXX fun[0] and fun.arguments[0] are equivalent. */
1394     if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
1395     *vp = fp->argv[slot];
1396     break;
1397     }
1398    
1399     return JS_TRUE;
1400     }
1401    
1402     /*
1403     * ECMA-262 specifies that length is a property of function object instances,
1404     * but we can avoid that space cost by delegating to a prototype property that
1405     * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes
1406     * a fresh length value based on the arity of the individual function object's
1407     * private data.
1408     *
1409     * The extensions below other than length, i.e., the ones not in ECMA-262,
1410     * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
1411     * with ECMA we must allow a delegating object to override them. Therefore to
1412     * avoid entraining garbage in Function.prototype slots, they must be resolved
1413     * in non-prototype function objects, wherefore the lazy_function_props table
1414     * and fun_resolve's use of it.
1415     */
1416     #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
1417    
1418     static JSPropertySpec function_props[] = {
1419     {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, fun_getProperty, JS_PropertyStub},
1420     {0,0,0,0,0}
1421     };
1422    
1423     typedef struct LazyFunctionProp {
1424     uint16 atomOffset;
1425     int8 tinyid;
1426     uint8 attrs;
1427     } LazyFunctionProp;
1428    
1429     /* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
1430     static LazyFunctionProp lazy_function_props[] = {
1431     {ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT},
1432     {ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT},
1433     {ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT},
1434     {ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT},
1435     };
1436    
1437     static JSBool
1438     fun_enumerate(JSContext *cx, JSObject *obj)
1439     {
1440     jsid prototypeId;
1441     JSObject *pobj;
1442     JSProperty *prop;
1443    
1444     prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1445     if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop))
1446     return JS_FALSE;
1447     if (prop)
1448     OBJ_DROP_PROPERTY(cx, pobj, prop);
1449     return JS_TRUE;
1450     }
1451    
1452     static JSBool
1453     fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
1454     JSObject **objp)
1455     {
1456     JSFunction *fun;
1457     JSAtom *atom;
1458     uintN i;
1459    
1460     if (!JSVAL_IS_STRING(id))
1461     return JS_TRUE;
1462    
1463     fun = GET_FUNCTION_PRIVATE(cx, obj);
1464    
1465     /*
1466     * No need to reflect fun.prototype in 'fun.prototype = ... '.
1467     */
1468     if (flags & JSRESOLVE_ASSIGNING)
1469     return JS_TRUE;
1470    
1471     /*
1472     * Ok, check whether id is 'prototype' and bootstrap the function object's
1473     * prototype property.
1474     */
1475     atom = cx->runtime->atomState.classPrototypeAtom;
1476     if (id == ATOM_KEY(atom)) {
1477     JSObject *proto;
1478    
1479     /*
1480     * Beware of the wacky case of a user function named Object -- trying
1481     * to find a prototype for that will recur back here _ad perniciem_.
1482     */
1483     if (fun->atom == CLASS_ATOM(cx, Object))
1484     return JS_TRUE;
1485    
1486     /*
1487     * Make the prototype object to have the same parent as the function
1488     * object itself.
1489     */
1490     proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj),
1491     0);
1492     if (!proto)
1493     return JS_FALSE;
1494    
1495     /*
1496     * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1497     * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1498     * native "system" constructors such as Object or Function. So lazily
1499     * set the former here in fun_resolve, but eagerly define the latter
1500     * in JS_InitClass, with the right attributes.
1501     */
1502     if (!js_SetClassPrototype(cx, obj, proto,
1503     JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
1504     cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1505     return JS_FALSE;
1506     }
1507     *objp = obj;
1508     return JS_TRUE;
1509     }
1510    
1511     for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
1512     LazyFunctionProp *lfp = &lazy_function_props[i];
1513    
1514     atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
1515     if (id == ATOM_KEY(atom)) {
1516     if (!js_DefineNativeProperty(cx, obj,
1517     ATOM_TO_JSID(atom), JSVAL_VOID,
1518     fun_getProperty, JS_PropertyStub,
1519     lfp->attrs, SPROP_HAS_SHORTID,
1520     lfp->tinyid, NULL)) {
1521     return JS_FALSE;
1522     }
1523     *objp = obj;
1524     return JS_TRUE;
1525     }
1526     }
1527    
1528     return JS_TRUE;
1529     }
1530    
1531     static JSBool
1532     fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1533     {
1534     switch (type) {
1535     case JSTYPE_FUNCTION:
1536     *vp = OBJECT_TO_JSVAL(obj);
1537     return JS_TRUE;
1538     default:
1539     return js_TryValueOf(cx, obj, type, vp);
1540     }
1541     }
1542    
1543     #if JS_HAS_XDR
1544    
1545     /* XXX store parent and proto, if defined */
1546 siliconforks 460 JSBool
1547     js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
1548 siliconforks 332 {
1549     JSContext *cx;
1550     JSFunction *fun;
1551 siliconforks 460 uint32 firstword; /* flag telling whether fun->atom is non-null,
1552     plus for fun->u.i.skipmin, fun->u.i.wrapper,
1553     and 14 bits reserved for future use */
1554     uintN nargs, nvars, nupvars, n;
1555     uint32 localsword; /* word for argument and variable counts */
1556     uint32 flagsword; /* word for fun->u.i.nupvars and fun->flags */
1557 siliconforks 332 JSTempValueRooter tvr;
1558     JSBool ok;
1559    
1560     cx = xdr->cx;
1561     if (xdr->mode == JSXDR_ENCODE) {
1562     fun = GET_FUNCTION_PRIVATE(cx, *objp);
1563     if (!FUN_INTERPRETED(fun)) {
1564     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1565     JSMSG_NOT_SCRIPTED_FUNCTION,
1566     JS_GetFunctionName(fun));
1567     return JS_FALSE;
1568     }
1569 siliconforks 460 if (fun->u.i.wrapper) {
1570     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1571     JSMSG_XDR_CLOSURE_WRAPPER,
1572     JS_GetFunctionName(fun));
1573     return JS_FALSE;
1574     }
1575     JS_ASSERT((fun->u.i.wrapper & ~1U) == 0);
1576     firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom;
1577 siliconforks 332 nargs = fun->nargs;
1578     nvars = fun->u.i.nvars;
1579 siliconforks 460 nupvars = fun->u.i.nupvars;
1580 siliconforks 332 localsword = (nargs << 16) | nvars;
1581 siliconforks 460 flagsword = (nupvars << 16) | fun->flags;
1582 siliconforks 332 } else {
1583     fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1584     if (!fun)
1585     return JS_FALSE;
1586     STOBJ_CLEAR_PARENT(FUN_OBJECT(fun));
1587     STOBJ_CLEAR_PROTO(FUN_OBJECT(fun));
1588     #ifdef __GNUC__
1589 siliconforks 460 nvars = nargs = nupvars = 0; /* quell GCC uninitialized warning */
1590 siliconforks 332 #endif
1591     }
1592    
1593     /* From here on, control flow must flow through label out. */
1594 siliconforks 460 MUST_FLOW_THROUGH("out");
1595 siliconforks 332 JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
1596     ok = JS_TRUE;
1597    
1598 siliconforks 460 if (!JS_XDRUint32(xdr, &firstword))
1599 siliconforks 332 goto bad;
1600 siliconforks 460 if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom))
1601 siliconforks 332 goto bad;
1602     if (!JS_XDRUint32(xdr, &localsword) ||
1603     !JS_XDRUint32(xdr, &flagsword)) {
1604     goto bad;
1605     }
1606    
1607     if (xdr->mode == JSXDR_DECODE) {
1608     nargs = localsword >> 16;
1609 siliconforks 460 nvars = uint16(localsword);
1610     JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
1611     nupvars = flagsword >> 16;
1612     fun->flags = uint16(flagsword);
1613     fun->u.i.skipmin = uint16(firstword >> 2);
1614     fun->u.i.wrapper = (firstword >> 1) & 1;
1615 siliconforks 332 }
1616    
1617     /* do arguments and local vars */
1618 siliconforks 460 n = nargs + nvars + nupvars;
1619 siliconforks 332 if (n != 0) {
1620     void *mark;
1621     uintN i;
1622     uintN bitmapLength;
1623     uint32 *bitmap;
1624     jsuword *names;
1625     JSAtom *name;
1626     JSLocalKind localKind;
1627    
1628     mark = JS_ARENA_MARK(&xdr->cx->tempPool);
1629    
1630     /*
1631     * From this point the control must flow via the label release_mark.
1632     *
1633     * To xdr the names we prefix the names with a bitmap descriptor and
1634     * then xdr the names as strings. For argument names (indexes below
1635     * nargs) the corresponding bit in the bitmap is unset when the name
1636     * is null. Such null names are not encoded or decoded. For variable
1637     * names (indexes starting from nargs) bitmap's bit is set when the
1638     * name is declared as const, not as ordinary var.
1639     * */
1640 siliconforks 460 MUST_FLOW_THROUGH("release_mark");
1641 siliconforks 332 bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
1642     JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
1643     bitmapLength * sizeof *bitmap);
1644     if (!bitmap) {
1645     js_ReportOutOfScriptQuota(xdr->cx);
1646     ok = JS_FALSE;
1647     goto release_mark;
1648     }
1649     if (xdr->mode == JSXDR_ENCODE) {
1650     names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool);
1651     if (!names) {
1652     ok = JS_FALSE;
1653     goto release_mark;
1654     }
1655     memset(bitmap, 0, bitmapLength * sizeof *bitmap);
1656     for (i = 0; i != n; ++i) {
1657     if (i < fun->nargs
1658     ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL
1659     : JS_LOCAL_NAME_IS_CONST(names[i])) {
1660     bitmap[i >> JS_BITS_PER_UINT32_LOG2] |=
1661     JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
1662     }
1663     }
1664     }
1665     #ifdef __GNUC__
1666     else {
1667     names = NULL; /* quell GCC uninitialized warning */
1668     }
1669     #endif
1670     for (i = 0; i != bitmapLength; ++i) {
1671     ok = JS_XDRUint32(xdr, &bitmap[i]);
1672     if (!ok)
1673     goto release_mark;
1674     }
1675     for (i = 0; i != n; ++i) {
1676     if (i < nargs &&
1677     !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
1678     JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) {
1679     if (xdr->mode == JSXDR_DECODE) {
1680     ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG);
1681     if (!ok)
1682     goto release_mark;
1683     } else {
1684     JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names[i]));
1685     }
1686     continue;
1687     }
1688     if (xdr->mode == JSXDR_ENCODE)
1689     name = JS_LOCAL_NAME_TO_ATOM(names[i]);
1690     ok = js_XDRStringAtom(xdr, &name);
1691     if (!ok)
1692     goto release_mark;
1693     if (xdr->mode == JSXDR_DECODE) {
1694     localKind = (i < nargs)
1695     ? JSLOCAL_ARG
1696 siliconforks 460 : (i < nargs + nvars)
1697     ? (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
1698     JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
1699     ? JSLOCAL_CONST
1700     : JSLOCAL_VAR)
1701     : JSLOCAL_UPVAR;
1702 siliconforks 332 ok = js_AddLocal(xdr->cx, fun, name, localKind);
1703     if (!ok)
1704     goto release_mark;
1705     }
1706     }
1707     ok = JS_TRUE;
1708    
1709     release_mark:
1710     JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
1711     if (!ok)
1712     goto out;
1713    
1714     if (xdr->mode == JSXDR_DECODE)
1715     js_FreezeLocalNames(cx, fun);
1716     }
1717    
1718     if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
1719     goto bad;
1720    
1721     if (xdr->mode == JSXDR_DECODE) {
1722     *objp = FUN_OBJECT(fun);
1723     #ifdef CHECK_SCRIPT_OWNER
1724     fun->u.i.script->owner = NULL;
1725     #endif
1726     js_CallNewScriptHook(cx, fun->u.i.script, fun);
1727     }
1728    
1729     out:
1730     JS_POP_TEMP_ROOT(cx, &tvr);
1731     return ok;
1732    
1733     bad:
1734     ok = JS_FALSE;
1735     goto out;
1736     }
1737    
1738     #else /* !JS_HAS_XDR */
1739    
1740 siliconforks 460 #define js_XDRFunctionObject NULL
1741 siliconforks 332
1742     #endif /* !JS_HAS_XDR */
1743    
1744     /*
1745     * [[HasInstance]] internal method for Function objects: fetch the .prototype
1746     * property of its 'this' parameter, and walks the prototype chain of v (only
1747     * if v is an object) returning true if .prototype is found.
1748     */
1749     static JSBool
1750     fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
1751     {
1752     jsval pval;
1753    
1754     if (!OBJ_GET_PROPERTY(cx, obj,
1755     ATOM_TO_JSID(cx->runtime->atomState
1756     .classPrototypeAtom),
1757     &pval)) {
1758     return JS_FALSE;
1759     }
1760    
1761     if (JSVAL_IS_PRIMITIVE(pval)) {
1762     /*
1763     * Throw a runtime error if instanceof is called on a function that
1764     * has a non-object as its .prototype value.
1765     */
1766     js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE,
1767     -1, OBJECT_TO_JSVAL(obj), NULL);
1768     return JS_FALSE;
1769     }
1770    
1771     return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
1772     }
1773    
1774     static void
1775     TraceLocalNames(JSTracer *trc, JSFunction *fun);
1776    
1777     static void
1778     DestroyLocalNames(JSContext *cx, JSFunction *fun);
1779    
1780     static void
1781     fun_trace(JSTracer *trc, JSObject *obj)
1782     {
1783     JSFunction *fun;
1784    
1785     /* A newborn function object may have a not yet initialized private slot. */
1786     fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
1787     if (!fun)
1788     return;
1789    
1790     if (FUN_OBJECT(fun) != obj) {
1791     /* obj is cloned function object, trace the original. */
1792     JS_CALL_TRACER(trc, FUN_OBJECT(fun), JSTRACE_OBJECT, "private");
1793     return;
1794     }
1795     if (fun->atom)
1796     JS_CALL_STRING_TRACER(trc, ATOM_TO_STRING(fun->atom), "atom");
1797     if (FUN_INTERPRETED(fun)) {
1798     if (fun->u.i.script)
1799     js_TraceScript(trc, fun->u.i.script);
1800     TraceLocalNames(trc, fun);
1801     }
1802     }
1803    
1804     static void
1805     fun_finalize(JSContext *cx, JSObject *obj)
1806     {
1807     JSFunction *fun;
1808    
1809     /* Ignore newborn and cloned function objects. */
1810     fun = (JSFunction *) JS_GetPrivate(cx, obj);
1811     if (!fun || FUN_OBJECT(fun) != obj)
1812     return;
1813    
1814     /*
1815     * Null-check of u.i.script is required since the parser sets interpreted
1816     * very early.
1817     */
1818     if (FUN_INTERPRETED(fun)) {
1819     if (fun->u.i.script)
1820     js_DestroyScript(cx, fun->u.i.script);
1821     DestroyLocalNames(cx, fun);
1822     }
1823     }
1824    
1825     static uint32
1826     fun_reserveSlots(JSContext *cx, JSObject *obj)
1827     {
1828     JSFunction *fun;
1829     uint32 nslots;
1830    
1831     /*
1832     * We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during
1833     * js_InitFunctionClass invocation the function is called before the
1834     * private slot of the function object is set.
1835     */
1836     fun = (JSFunction *) JS_GetPrivate(cx, obj);
1837     nslots = 0;
1838     if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {
1839 siliconforks 460 if (fun->u.i.nupvars != 0)
1840 siliconforks 332 nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;
1841     if (fun->u.i.script->regexpsOffset != 0)
1842     nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;
1843     }
1844     return nslots;
1845     }
1846    
1847     /*
1848     * Reserve two slots in all function objects for XPConnect. Note that this
1849     * does not bloat every instance, only those on which reserved slots are set,
1850     * and those on which ad-hoc properties are defined.
1851     */
1852     JS_FRIEND_DATA(JSClass) js_FunctionClass = {
1853     js_Function_str,
1854     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) |
1855     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
1856     JS_PropertyStub, JS_PropertyStub,
1857     JS_PropertyStub, JS_PropertyStub,
1858     fun_enumerate, (JSResolveOp)fun_resolve,
1859     fun_convert, fun_finalize,
1860     NULL, NULL,
1861     NULL, NULL,
1862 siliconforks 460 js_XDRFunctionObject, fun_hasInstance,
1863 siliconforks 332 JS_CLASS_TRACE(fun_trace), fun_reserveSlots
1864     };
1865    
1866     static JSBool
1867     fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
1868     {
1869     jsval fval;
1870     JSObject *obj;
1871     JSFunction *fun;
1872     JSString *str;
1873    
1874     fval = JS_THIS(cx, vp);
1875     if (JSVAL_IS_NULL(fval))
1876     return JS_FALSE;
1877    
1878     if (!VALUE_IS_FUNCTION(cx, fval)) {
1879     /*
1880     * If we don't have a function to start off with, try converting the
1881     * object to a function. If that doesn't work, complain.
1882     */
1883     if (!JSVAL_IS_PRIMITIVE(fval)) {
1884     obj = JSVAL_TO_OBJECT(fval);
1885     if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
1886     &fval)) {
1887     return JS_FALSE;
1888     }
1889     vp[1] = fval;
1890     }
1891     if (!VALUE_IS_FUNCTION(cx, fval)) {
1892     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1893     JSMSG_INCOMPATIBLE_PROTO,
1894     js_Function_str, js_toString_str,
1895     JS_GetTypeName(cx, JS_TypeOfValue(cx, fval)));
1896     return JS_FALSE;
1897     }
1898     }
1899    
1900     obj = JSVAL_TO_OBJECT(fval);
1901     if (argc != 0) {
1902     indent = js_ValueToECMAUint32(cx, &vp[2]);
1903     if (JSVAL_IS_NULL(vp[2]))
1904     return JS_FALSE;
1905     }
1906    
1907     JS_ASSERT(JS_ObjectIsFunction(cx, obj));
1908     fun = GET_FUNCTION_PRIVATE(cx, obj);
1909     if (!fun)
1910     return JS_TRUE;
1911     str = JS_DecompileFunction(cx, fun, (uintN)indent);
1912     if (!str)
1913     return JS_FALSE;
1914     *vp = STRING_TO_JSVAL(str);
1915     return JS_TRUE;
1916     }
1917    
1918     static JSBool
1919     fun_toString(JSContext *cx, uintN argc, jsval *vp)
1920     {
1921     return fun_toStringHelper(cx, 0, argc, vp);
1922     }
1923    
1924     #if JS_HAS_TOSOURCE
1925     static JSBool
1926     fun_toSource(JSContext *cx, uintN argc, jsval *vp)
1927     {
1928     return fun_toStringHelper(cx, JS_DONT_PRETTY_PRINT, argc, vp);
1929     }
1930     #endif
1931    
1932 siliconforks 460 JS_REQUIRES_STACK JSBool
1933 siliconforks 399 js_fun_call(JSContext *cx, uintN argc, jsval *vp)
1934 siliconforks 332 {
1935     JSObject *obj;
1936     jsval fval, *argv, *invokevp;
1937     JSString *str;
1938     void *mark;
1939     JSBool ok;
1940    
1941     obj = JS_THIS_OBJECT(cx, vp);
1942     if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
1943     return JS_FALSE;
1944     fval = vp[1];
1945    
1946     if (!VALUE_IS_FUNCTION(cx, fval)) {
1947     str = JS_ValueToString(cx, fval);
1948     if (str) {
1949     const char *bytes = js_GetStringBytes(cx, str);
1950    
1951     if (bytes) {
1952     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1953     JSMSG_INCOMPATIBLE_PROTO,
1954 siliconforks 399 js_Function_str, js_call_str,
1955 siliconforks 332 bytes);
1956     }
1957     }
1958     return JS_FALSE;
1959     }
1960    
1961     argv = vp + 2;
1962     if (argc == 0) {
1963     /* Call fun with its global object as the 'this' param if no args. */
1964     obj = NULL;
1965     } else {
1966     /* Otherwise convert the first arg to 'this' and skip over it. */
1967     if (!JSVAL_IS_PRIMITIVE(argv[0]))
1968     obj = JSVAL_TO_OBJECT(argv[0]);
1969     else if (!js_ValueToObject(cx, argv[0], &obj))
1970     return JS_FALSE;
1971     argc--;
1972     argv++;
1973     }
1974    
1975     /* Allocate stack space for fval, obj, and the args. */
1976     invokevp = js_AllocStack(cx, 2 + argc, &mark);
1977     if (!invokevp)
1978     return JS_FALSE;
1979    
1980     /* Push fval, obj, and the args. */
1981     invokevp[0] = fval;
1982     invokevp[1] = OBJECT_TO_JSVAL(obj);
1983     memcpy(invokevp + 2, argv, argc * sizeof *argv);
1984    
1985     ok = js_Invoke(cx, argc, invokevp, 0);
1986     *vp = *invokevp;
1987     js_FreeStack(cx, mark);
1988     return ok;
1989     }
1990    
1991 siliconforks 460 JS_REQUIRES_STACK JSBool
1992 siliconforks 332 js_fun_apply(JSContext *cx, uintN argc, jsval *vp)
1993     {
1994     JSObject *obj, *aobj;
1995     jsval fval, *invokevp, *sp;
1996     JSString *str;
1997     jsuint length;
1998     JSBool arraylike, ok;
1999     void *mark;
2000     uintN i;
2001    
2002     if (argc == 0) {
2003     /* Will get globalObject as 'this' and no other arguments. */
2004 siliconforks 399 return js_fun_call(cx, argc, vp);
2005 siliconforks 332 }
2006    
2007     obj = JS_THIS_OBJECT(cx, vp);
2008     if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
2009     return JS_FALSE;
2010     fval = vp[1];
2011    
2012     if (!VALUE_IS_FUNCTION(cx, fval)) {
2013     str = JS_ValueToString(cx, fval);
2014     if (str) {
2015     const char *bytes = js_GetStringBytes(cx, str);
2016    
2017     if (bytes) {
2018     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2019     JSMSG_INCOMPATIBLE_PROTO,
2020 siliconforks 399 js_Function_str, js_apply_str,
2021 siliconforks 332 bytes);
2022     }
2023     }
2024     return JS_FALSE;
2025     }
2026    
2027     /* Quell GCC overwarnings. */
2028     aobj = NULL;
2029     length = 0;
2030    
2031     if (argc >= 2) {
2032     /* If the 2nd arg is null or void, call the function with 0 args. */
2033     if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) {
2034     argc = 0;
2035     } else {
2036     /* The second arg must be an array (or arguments object). */
2037     arraylike = JS_FALSE;
2038     if (!JSVAL_IS_PRIMITIVE(vp[3])) {
2039     aobj = JSVAL_TO_OBJECT(vp[3]);
2040     if (!js_IsArrayLike(cx, aobj, &arraylike, &length))
2041     return JS_FALSE;
2042     }
2043     if (!arraylike) {
2044     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2045 siliconforks 399 JSMSG_BAD_APPLY_ARGS, js_apply_str);
2046 siliconforks 332 return JS_FALSE;
2047     }
2048     }
2049     }
2050    
2051     /* Convert the first arg to 'this' and skip over it. */
2052     if (!JSVAL_IS_PRIMITIVE(vp[2]))
2053     obj = JSVAL_TO_OBJECT(vp[2]);
2054     else if (!js_ValueToObject(cx, vp[2], &obj))
2055     return JS_FALSE;
2056    
2057     /* Allocate stack space for fval, obj, and the args. */
2058     argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
2059     invokevp = js_AllocStack(cx, 2 + argc, &mark);
2060     if (!invokevp)
2061     return JS_FALSE;
2062    
2063     /* Push fval, obj, and aobj's elements as args. */
2064     sp = invokevp;
2065     *sp++ = fval;
2066     *sp++ = OBJECT_TO_JSVAL(obj);
2067     for (i = 0; i < argc; i++) {
2068     ok = JS_GetElement(cx, aobj, (jsint)i, sp);
2069     if (!ok)
2070     goto out;
2071     sp++;
2072     }
2073    
2074     ok = js_Invoke(cx, argc, invokevp, 0);
2075     *vp = *invokevp;
2076     out:
2077     js_FreeStack(cx, mark);
2078     return ok;
2079     }
2080    
2081     #ifdef NARCISSUS
2082 siliconforks 460 static JS_REQUIRES_STACK JSBool
2083 siliconforks 332 fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
2084     {
2085     JSObject *aobj;
2086     uintN length, i;
2087     void *mark;
2088     jsval *invokevp, *sp;
2089     JSBool ok;
2090    
2091     if (JSVAL_IS_PRIMITIVE(vp[2]) ||
2092     (aobj = JSVAL_TO_OBJECT(vp[2]),
2093     OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass &&
2094     OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) {
2095     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2096     JSMSG_BAD_APPLY_ARGS, "__applyConstruct__");
2097     return JS_FALSE;
2098     }
2099    
2100     if (!js_GetLengthProperty(cx, aobj, &length))
2101     return JS_FALSE;
2102    
2103     if (length >= ARRAY_INIT_LIMIT)
2104     length = ARRAY_INIT_LIMIT - 1;
2105     invokevp = js_AllocStack(cx, 2 + length, &mark);
2106     if (!invokevp)
2107     return JS_FALSE;
2108    
2109     sp = invokevp;
2110     *sp++ = vp[1];
2111     *sp++ = JSVAL_NULL; /* this is filled automagically */
2112     for (i = 0; i < length; i++) {
2113     ok = JS_GetElement(cx, aobj, (jsint)i, sp);
2114     if (!ok)
2115     goto out;
2116     sp++;
2117     }
2118    
2119     ok = js_InvokeConstructor(cx, length, JS_TRUE, invokevp);
2120     *vp = *invokevp;
2121     out:
2122     js_FreeStack(cx, mark);
2123     return ok;
2124     }
2125     #endif
2126    
2127     static JSFunctionSpec function_methods[] = {
2128     #if JS_HAS_TOSOURCE
2129     JS_FN(js_toSource_str, fun_toSource, 0,0),
2130     #endif
2131     JS_FN(js_toString_str, fun_toString, 0,0),
2132 siliconforks 399 JS_FN(js_apply_str, js_fun_apply, 2,0),
2133     JS_FN(js_call_str, js_fun_call, 1,0),
2134 siliconforks 332 #ifdef NARCISSUS
2135 siliconforks 399 JS_FN("__applyConstructor__", fun_applyConstructor, 1,0),
2136 siliconforks 332 #endif
2137     JS_FS_END
2138     };
2139    
2140     static JSBool
2141     Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2142     {
2143     JSFunction *fun;
2144     JSObject *parent;
2145 siliconforks 460 JSStackFrame *fp, *caller;
2146 siliconforks 332 uintN i, n, lineno;
2147     JSAtom *atom;
2148     const char *filename;
2149     JSBool ok;
2150     JSString *str, *arg;
2151     JSTokenStream ts;
2152     JSPrincipals *principals;
2153     jschar *collected_args, *cp;
2154     void *mark;
2155     size_t arg_length, args_length, old_args_length;
2156     JSTokenType tt;
2157    
2158 siliconforks 460 if (!JS_IsConstructing(cx)) {
2159 siliconforks 332 obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);
2160     if (!obj)
2161     return JS_FALSE;
2162     *rval = OBJECT_TO_JSVAL(obj);
2163     } else {
2164     /*
2165     * The constructor is called before the private slot is initialized so
2166     * we must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here.
2167     */
2168     if (JS_GetPrivate(cx, obj))
2169     return JS_TRUE;
2170     }
2171    
2172     /*
2173     * NB: (new Function) is not lexically closed by its caller, it's just an
2174     * anonymous function in the top-level scope that its constructor inhabits.
2175     * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2176     * and so would a call to f from another top-level's script or function.
2177     *
2178     * In older versions, before call objects, a new Function was adopted by
2179     * its running context's globalObject, which might be different from the
2180     * top-level reachable from scopeChain (in HTML frames, e.g.).
2181     */
2182     parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
2183    
2184     fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
2185     parent, cx->runtime->atomState.anonymousAtom);
2186    
2187     if (!fun)
2188     return JS_FALSE;
2189    
2190     /*
2191     * Function is static and not called directly by other functions in this
2192     * file, therefore it is callable only as a native function by js_Invoke.
2193     * Find the scripted caller, possibly skipping other native frames such as
2194     * are built for Function.prototype.call or .apply activations that invoke
2195     * Function indirectly from a script.
2196     */
2197 siliconforks 460 fp = js_GetTopStackFrame(cx);
2198 siliconforks 332 JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
2199 siliconforks 460 caller = js_GetScriptedCaller(cx, fp);
2200 siliconforks 332 if (caller) {
2201     principals = JS_EvalFramePrincipals(cx, fp, caller);
2202     filename = js_ComputeFilename(cx, caller, principals, &lineno);
2203     } else {
2204     filename = NULL;
2205     lineno = 0;
2206     principals = NULL;
2207     }
2208    
2209     /* Belt-and-braces: check that the caller has access to parent. */
2210     if (!js_CheckPrincipalsAccess(cx, parent, principals,
2211     CLASS_ATOM(cx, Function))) {
2212     return JS_FALSE;
2213     }
2214    
2215     n = argc ? argc - 1 : 0;
2216     if (n > 0) {
2217     enum { OK, BAD, BAD_FORMAL } state;
2218    
2219     /*
2220     * Collect the function-argument arguments into one string, separated
2221     * by commas, then make a tokenstream from that string, and scan it to
2222     * get the arguments. We need to throw the full scanner at the
2223     * problem, because the argument string can legitimately contain
2224     * comments and linefeeds. XXX It might be better to concatenate
2225     * everything up into a function definition and pass it to the
2226     * compiler, but doing it this way is less of a delta from the old
2227     * code. See ECMA 15.3.2.1.
2228     */
2229     state = BAD_FORMAL;
2230     args_length = 0;
2231     for (i = 0; i < n; i++) {
2232     /* Collect the lengths for all the function-argument arguments. */
2233     arg = js_ValueToString(cx, argv[i]);
2234     if (!arg)
2235     return JS_FALSE;
2236     argv[i] = STRING_TO_JSVAL(arg);
2237    
2238     /*
2239     * Check for overflow. The < test works because the maximum
2240     * JSString length fits in 2 fewer bits than size_t has.
2241     */
2242     old_args_length = args_length;
2243     args_length = old_args_length + JSSTRING_LENGTH(arg);
2244     if (args_length < old_args_length) {
2245     js_ReportAllocationOverflow(cx);
2246     return JS_FALSE;
2247     }
2248     }
2249    
2250     /* Add 1 for each joining comma and check for overflow (two ways). */
2251     old_args_length = args_length;
2252     args_length = old_args_length + n - 1;
2253     if (args_length < old_args_length ||
2254     args_length >= ~(size_t)0 / sizeof(jschar)) {
2255     js_ReportAllocationOverflow(cx);
2256     return JS_FALSE;
2257     }
2258    
2259     /*
2260     * Allocate a string to hold the concatenated arguments, including room
2261     * for a terminating 0. Mark cx->tempPool for later release, to free
2262     * collected_args and its tokenstream in one swoop.
2263     */
2264     mark = JS_ARENA_MARK(&cx->tempPool);
2265     JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
2266     (args_length+1) * sizeof(jschar));
2267     if (!cp) {
2268     js_ReportOutOfScriptQuota(cx);
2269     return JS_FALSE;
2270     }
2271     collected_args = cp;
2272    
2273     /*
2274     * Concatenate the arguments into the new string, separated by commas.
2275     */
2276     for (i = 0; i < n; i++) {
2277     arg = JSVAL_TO_STRING(argv[i]);
2278     arg_length = JSSTRING_LENGTH(arg);
2279     (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
2280     cp += arg_length;
2281    
2282     /* Add separating comma or terminating 0. */
2283     *cp++ = (i + 1 < n) ? ',' : 0;
2284     }
2285    
2286     /* Initialize a tokenstream that reads from the given string. */
2287     if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
2288     NULL, filename, lineno)) {
2289     JS_ARENA_RELEASE(&cx->tempPool, mark);
2290     return JS_FALSE;
2291     }
2292    
2293     /* The argument string may be empty or contain no tokens. */
2294     tt = js_GetToken(cx, &ts);
2295     if (tt != TOK_EOF) {
2296     for (;;) {
2297     /*
2298     * Check that it's a name. This also implicitly guards against
2299     * TOK_ERROR, which was already reported.
2300     */
2301     if (tt != TOK_NAME)
2302     goto after_args;
2303    
2304     /*
2305     * Get the atom corresponding to the name from the token
2306     * stream; we're assured at this point that it's a valid
2307     * identifier.
2308     */
2309     atom = CURRENT_TOKEN(&ts).t_atom;
2310    
2311     /* Check for a duplicate parameter name. */
2312     if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
2313     const char *name;
2314    
2315     name = js_AtomToPrintableString(cx, atom);
2316     ok = name &&
2317     js_ReportCompileErrorNumber(cx, &ts, NULL,
2318     JSREPORT_WARNING |
2319     JSREPORT_STRICT,
2320     JSMSG_DUPLICATE_FORMAL,
2321     name);
2322     if (!ok)
2323     goto after_args;
2324     }
2325     if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG))
2326     goto after_args;
2327    
2328     /*
2329     * Get the next token. Stop on end of stream. Otherwise
2330     * insist on a comma, get another name, and iterate.
2331     */
2332     tt = js_GetToken(cx, &ts);
2333     if (tt == TOK_EOF)
2334     break;
2335     if (tt != TOK_COMMA)
2336     goto after_args;
2337     tt = js_GetToken(cx, &ts);
2338     }
2339     }
2340    
2341     state = OK;
2342     after_args:
2343     if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) {
2344     /*
2345     * Report "malformed formal parameter" iff no illegal char or
2346     * similar scanner error was already reported.
2347     */
2348     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2349     JSMSG_BAD_FORMAL);
2350     }
2351     js_CloseTokenStream(cx, &ts);
2352     JS_ARENA_RELEASE(&cx->tempPool, mark);
2353     if (state != OK)
2354     return JS_FALSE;
2355     }
2356    
2357     if (argc) {
2358     str = js_ValueToString(cx, argv[argc-1]);
2359     if (!str)
2360     return JS_FALSE;
2361     argv[argc-1] = STRING_TO_JSVAL(str);
2362     } else {
2363     str = cx->runtime->emptyString;
2364     }
2365    
2366 siliconforks 460 return JSCompiler::compileFunctionBody(cx, fun, principals,
2367     JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
2368     filename, lineno);
2369 siliconforks 332 }
2370    
2371     JSObject *
2372     js_InitFunctionClass(JSContext *cx, JSObject *obj)
2373     {
2374     JSObject *proto;
2375     JSFunction *fun;
2376    
2377     proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
2378     function_props, function_methods, NULL, NULL);
2379     if (!proto)
2380     return NULL;
2381     fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
2382     if (!fun)
2383     goto bad;
2384 siliconforks 399 fun->u.i.script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0);
2385 siliconforks 332 if (!fun->u.i.script)
2386     goto bad;
2387     fun->u.i.script->code[0] = JSOP_STOP;
2388 siliconforks 399 *SCRIPT_NOTES(fun->u.i.script) = SRC_NULL;
2389 siliconforks 332 #ifdef CHECK_SCRIPT_OWNER
2390     fun->u.i.script->owner = NULL;
2391     #endif
2392     return proto;
2393    
2394     bad:
2395     cx->weakRoots.newborn[GCX_OBJECT] = NULL;
2396     return NULL;
2397     }
2398    
2399     JSFunction *
2400     js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
2401     uintN flags, JSObject *parent, JSAtom *atom)
2402     {
2403     JSFunction *fun;
2404    
2405     if (funobj) {
2406     JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
2407     OBJ_SET_PARENT(cx, funobj, parent);
2408     } else {
2409     funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent, 0);
2410     if (!funobj)
2411     return NULL;
2412     }
2413     JS_ASSERT(JSVAL_IS_VOID(funobj->fslots[JSSLOT_PRIVATE]));
2414     fun = (JSFunction *) funobj;
2415    
2416     /* Initialize all function members. */
2417     fun->nargs = nargs;
2418 siliconforks 460 fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRACEABLE);
2419     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
2420 siliconforks 332 JS_ASSERT(!native);
2421     JS_ASSERT(nargs == 0);
2422     fun->u.i.nvars = 0;
2423     fun->u.i.nupvars = 0;
2424 siliconforks 460 fun->u.i.skipmin = 0;
2425     fun->u.i.wrapper = false;
2426 siliconforks 332 fun->u.i.script = NULL;
2427     #ifdef DEBUG
2428     fun->u.i.names.taggedAtom = 0;
2429     #endif
2430     } else {
2431     fun->u.n.extra = 0;
2432     fun->u.n.spare = 0;
2433 siliconforks 460 fun->u.n.clasp = NULL;
2434 siliconforks 399 if (flags & JSFUN_TRACEABLE) {
2435     #ifdef JS_TRACER
2436 siliconforks 460 JSTraceableNative *trcinfo =
2437     JS_FUNC_TO_DATA_PTR(JSTraceableNative *, native);
2438 siliconforks 399 fun->u.n.native = (JSNative) trcinfo->native;
2439 siliconforks 460 fun->u.n.trcinfo = trcinfo;
2440 siliconforks 399 #else
2441 siliconforks 460 fun->u.n.trcinfo = NULL;
2442 siliconforks 399 #endif
2443     } else {
2444     fun->u.n.native = native;
2445 siliconforks 460 fun->u.n.trcinfo = NULL;
2446 siliconforks 399 }
2447 siliconforks 460 JS_ASSERT(fun->u.n.native);
2448 siliconforks 332 }
2449     fun->atom = atom;
2450    
2451     /* Set private to self to indicate non-cloned fully initialized function. */
2452     FUN_OBJECT(fun)->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
2453     return fun;
2454     }
2455    
2456     JSObject *
2457     js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
2458     {
2459     /*
2460 siliconforks 460 * The cloned function object does not need the extra JSFunction members
2461     * beyond JSObject as it points to fun via the private slot.
2462 siliconforks 332 */
2463 siliconforks 460 JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
2464     sizeof(JSObject));
2465 siliconforks 332 if (!clone)
2466     return NULL;
2467     clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
2468     return clone;
2469     }
2470    
2471 siliconforks 460 JSObject *
2472     js_NewFlatClosure(JSContext *cx, JSFunction *fun)
2473     {
2474     JS_ASSERT(FUN_FLAT_CLOSURE(fun));
2475    
2476     JSObject *closure = js_CloneFunctionObject(cx, fun, cx->fp->scopeChain);
2477     if (!closure || fun->u.i.script->upvarsOffset == 0)
2478     return closure;
2479    
2480     uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
2481     JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
2482     nslots += fun_reserveSlots(cx, closure);
2483     if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE))
2484     return NULL;
2485    
2486     JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
2487     JS_ASSERT(uva->length <= size_t(closure->dslots[-1]));
2488    
2489     uintN level = fun->u.i.script->staticLevel;
2490     for (uint32 i = 0, n = uva->length; i < n; i++)
2491     closure->dslots[i] = js_GetUpvar(cx, level, uva->vector[i]);
2492    
2493     return closure;
2494     }
2495    
2496     JSObject *
2497     js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
2498     {
2499     JS_ASSERT(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT);
2500     JS_ASSERT(!cx->fp->fun->optimizedClosure());
2501    
2502     return WrapEscapingClosure(cx, cx->fp, FUN_OBJECT(fun), fun);
2503     }
2504    
2505 siliconforks 332 JSFunction *
2506     js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
2507     uintN nargs, uintN attrs)
2508     {
2509 siliconforks 460 JSPropertyOp gsop;
2510 siliconforks 332 JSFunction *fun;
2511    
2512 siliconforks 460 if (attrs & JSFUN_STUB_GSOPS) {
2513     /*
2514     * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2515     * the defined property's attributes. This allows us to encode another,
2516     * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2517     * for more on this.
2518     */
2519     attrs &= ~JSFUN_STUB_GSOPS;
2520     gsop = JS_PropertyStub;
2521     } else {
2522     gsop = NULL;
2523     }
2524 siliconforks 332 fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
2525     if (!fun)
2526     return NULL;
2527     if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2528     OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
2529     gsop, gsop,
2530