Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsfun.cpp
1 /* -*- 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 <string.h>
45 #include "jstypes.h"
46 #include "jsstdint.h"
47 #include "jsbit.h"
48 #include "jsutil.h"
49 #include "jsapi.h"
50 #include "jsarray.h"
51 #include "jsatom.h"
52 #include "jsbool.h"
53 #include "jsbuiltins.h"
54 #include "jscntxt.h"
55 #include "jsversion.h"
56 #include "jsemit.h"
57 #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 "jspropertytree.h"
66 #include "jsproxy.h"
67 #include "jsscan.h"
68 #include "jsscope.h"
69 #include "jsscript.h"
70 #include "jsstr.h"
71 #include "jsexn.h"
72 #include "jsstaticcheck.h"
73 #include "jstracer.h"
74
75 #if JS_HAS_GENERATORS
76 # include "jsiter.h"
77 #endif
78
79 #if JS_HAS_XDR
80 # include "jsxdrapi.h"
81 #endif
82
83 #ifdef JS_METHODJIT
84 #include "methodjit/MethodJIT.h"
85 #endif
86
87 #include "jsatominlines.h"
88 #include "jscntxtinlines.h"
89 #include "jsfuninlines.h"
90 #include "jsinterpinlines.h"
91 #include "jsobjinlines.h"
92 #include "jsscriptinlines.h"
93
94 using namespace js;
95 using namespace js::gc;
96
97 inline JSObject *
98 JSObject::getThrowTypeError() const
99 {
100     return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR).toObject();
101 }
102
103 JSBool
104 js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
105 {
106     JSObject *argsobj;
107
108     if (fp->hasOverriddenArgs()) {
109         JS_ASSERT(fp->hasCallObj());
110         jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
111         return fp->callObj().getProperty(cx, id, vp);
112     }
113     argsobj = js_GetArgsObject(cx, fp);
114     if (!argsobj)
115         return JS_FALSE;
116     vp->setObject(*argsobj);
117     return JS_TRUE;
118 }
119
120 JSBool
121 js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
122 {
123     JS_ASSERT(fp->isFunctionFrame());
124
125     if (fp->hasOverriddenArgs()) {
126         JS_ASSERT(fp->hasCallObj());
127
128         jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
129         Value v;
130         if (!fp->callObj().getProperty(cx, argumentsid, &v))
131             return false;
132
133         JSObject *obj;
134         if (v.isPrimitive()) {
135             obj = js_ValueToNonNullObject(cx, v);
136             if (!obj)
137                 return false;
138         } else {
139             obj = &v.toObject();
140         }
141         return obj->getProperty(cx, id, vp);
142     }
143
144     vp->setUndefined();
145     if (JSID_IS_INT(id)) {
146         uint32 arg = uint32(JSID_TO_INT(id));
147         JSObject *argsobj = fp->maybeArgsObj();
148         if (arg < fp->numActualArgs()) {
149             if (argsobj) {
150                 if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
151                     return argsobj->getProperty(cx, id, vp);
152             }
153             *vp = fp->canonicalActualArg(arg);
154         } else {
155             /*
156              * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
157              * storage between the formal parameter and arguments[k] for all
158              * fp->argc <= k && k < fp->fun->nargs.  For example, in
159              *
160              *   function f(x) { x = 42; return arguments[0]; }
161              *   f();
162              *
163              * the call to f should return undefined, not 42.  If fp->argsobj
164              * is null at this point, as it would be in the example, return
165              * undefined in *vp.
166              */
167             if (argsobj)
168                 return argsobj->getProperty(cx, id, vp);
169         }
170     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
171         JSObject *argsobj = fp->maybeArgsObj();
172         if (argsobj && argsobj->isArgsLengthOverridden())
173             return argsobj->getProperty(cx, id, vp);
174         vp->setInt32(fp->numActualArgs());
175     }
176     return true;
177 }
178
179 static JSObject *
180 NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
181 {
182     JSObject *proto;
183     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
184         return NULL;
185
186     JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2);
187     JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
188     if (!argsobj)
189         return NULL;
190
191     ArgumentsData *data = (ArgumentsData *)
192         cx->malloc(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
193     if (!data)
194         return NULL;
195     SetValueRangeToUndefined(data->slots, argc);
196
197     /* Can't fail from here on, so initialize everything in argsobj. */
198     argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
199                   ? &StrictArgumentsClass
200                   : &js_ArgumentsClass,
201                   proto, parent, NULL, false);
202
203     argsobj->setMap(cx->compartment->emptyArgumentsShape);
204
205     argsobj->setArgsLength(argc);
206     argsobj->setArgsData(data);
207     data->callee.setObject(callee);
208
209     return argsobj;
210 }
211
212 struct STATIC_SKIP_INFERENCE PutArg
213 {
214     PutArg(Value *dst) : dst(dst) {}
215     Value *dst;
216     void operator()(uintN, Value *src) {
217         if (!dst->isMagic(JS_ARGS_HOLE))
218             *dst = *src;
219         ++dst;
220     }
221 };
222
223 JSObject *
224 js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
225 {
226     /*
227      * We must be in a function activation; the function must be lightweight
228      * or else fp must have a variable object.
229      */
230     JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
231
232     while (fp->isEvalOrDebuggerFrame())
233         fp = fp->prev();
234
235     /* Create an arguments object for fp only if it lacks one. */
236     if (fp->hasArgsObj())
237         return &fp->argsObj();
238
239     /* Compute the arguments object's parent slot from fp's scope chain. */
240     JSObject *global = fp->scopeChain().getGlobal();
241     JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee());
242     if (!argsobj)
243         return argsobj;
244
245     /*
246      * Strict mode functions have arguments objects that copy the initial
247      * actual parameter values.  It is the caller's responsibility to get the
248      * arguments object before any parameters are modified!  (The emitter
249      * ensures this by synthesizing an arguments access at the start of any
250      * strict mode function that contains an assignment to a parameter, or
251      * that calls eval.)  Non-strict mode arguments use the frame pointer to
252      * retrieve up-to-date parameter values.
253      */
254     if (argsobj->isStrictArguments())
255         fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
256     else
257         argsobj->setPrivate(fp);
258
259     fp->setArgsObj(*argsobj);
260     return argsobj;
261 }
262
263 void
264 js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
265 {
266     JSObject &argsobj = fp->argsObj();
267     if (argsobj.isNormalArguments()) {
268         JS_ASSERT(argsobj.getPrivate() == fp);
269         fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots));
270         argsobj.setPrivate(NULL);
271     } else {
272         JS_ASSERT(!argsobj.getPrivate());
273     }
274     fp->clearArgsObj();
275 }
276
277 #ifdef JS_TRACER
278
279 /*
280  * Traced versions of js_GetArgsObject and js_PutArgsObject.
281  */
282 JSObject * JS_FASTCALL
283 js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
284 {
285     JSObject *argsobj = NewArguments(cx, parent, argc, *callee);
286     if (!argsobj)
287         return NULL;
288
289     if (argsobj->isStrictArguments()) {
290         /*
291          * Strict mode callers must copy arguments into the created arguments
292          * object. The trace-JITting code is in TraceRecorder::newArguments.
293          */
294         JS_ASSERT(!argsobj->getPrivate());
295     } else {
296         argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
297     }
298
299     return argsobj;
300 }
301 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UINT32, OBJECT,
302                      0, nanojit::ACCSET_STORE_ANY)
303
304 /* FIXME change the return type to void. */
305 JSBool JS_FASTCALL
306 js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
307 {
308     JS_ASSERT(argsobj->isNormalArguments());
309     JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
310
311     /*
312      * TraceRecorder::putActivationObjects builds a single, contiguous array of
313      * the arguments, regardless of whether #actuals > #formals so there is no
314      * need to worry about actual vs. formal arguments.
315      */
316     Value *srcend = args + argsobj->getArgsInitialLength();
317     Value *dst = argsobj->getArgsData()->slots;
318     for (Value *src = args; src != srcend; ++src, ++dst) {
319         if (!dst->isMagic(JS_ARGS_HOLE))
320             *dst = *src;
321     }
322
323     argsobj->setPrivate(NULL);
324     return true;
325 }
326 JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
327                      nanojit::ACCSET_STORE_ANY)
328
329 #endif /* JS_TRACER */
330
331 static JSBool
332 args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
333 {
334     JS_ASSERT(obj->isArguments());
335
336     if (JSID_IS_INT(id)) {
337         uintN arg = uintN(JSID_TO_INT(id));
338         if (arg < obj->getArgsInitialLength())
339             obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE));
340     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
341         obj->setArgsLengthOverridden();
342     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
343         obj->setArgsCallee(MagicValue(JS_ARGS_HOLE));
344     }
345     return true;
346 }
347
348 static JS_REQUIRES_STACK JSObject *
349 WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
350 {
351     JS_ASSERT(fun->optimizedClosure());
352     JS_ASSERT(!fun->u.i.wrapper);
353
354     /*
355      * We do not attempt to reify Call and Block objects on demand for outer
356      * scopes. This could be done (see the "v8" patch in bug 494235) but it is
357      * fragile in the face of ongoing compile-time optimization. Instead, the
358      * _DBG* opcodes used by wrappers created here must cope with unresolved
359      * upvars and throw them as reference errors. Caveat debuggers!
360      */
361     JSObject *scopeChain = GetScopeChain(cx, fp);
362     if (!scopeChain)
363         return NULL;
364
365     JSObject *wfunobj = NewFunction(cx, scopeChain);
366     if (!wfunobj)
367         return NULL;
368     AutoObjectRooter tvr(cx, wfunobj);
369
370     JSFunction *wfun = (JSFunction *) wfunobj;
371     wfunobj->setPrivate(wfun);
372     wfun->nargs = fun->nargs;
373     wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
374     wfun->u.i.skipmin = fun->u.i.skipmin;
375     wfun->u.i.wrapper = true;
376     wfun->u.i.script = NULL;
377     wfun->atom = fun->atom;
378
379     JSScript *script = fun->script();
380     jssrcnote *snbase = script->notes();
381     jssrcnote *sn = snbase;
382     while (!SN_IS_TERMINATOR(sn))
383         sn = SN_NEXT(sn);
384     uintN nsrcnotes = (sn - snbase) + 1;
385
386     /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
387     JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes,
388                                             script->atomMap.length,
389                                             JSScript::isValidOffset(script->objectsOffset)
390                                             ? script->objects()->length
391                                             : 0,
392                                             script->bindings.countUpvars(),
393                                             JSScript::isValidOffset(script->regexpsOffset)
394                                             ? script->regexps()->length
395                                             : 0,
396                                             JSScript::isValidOffset(script->trynotesOffset)
397                                             ? script->trynotes()->length
398                                             : 0,
399                                             JSScript::isValidOffset(script->constOffset)
400                                             ? script->consts()->length
401                                             : 0,
402                                             JSScript::isValidOffset(script->globalsOffset)
403                                             ? script->globals()->length
404                                             : 0,
405                                             script->nClosedArgs,
406                                             script->nClosedVars,
407                                             script->getVersion());
408     if (!wscript)
409         return NULL;
410
411     memcpy(wscript->code, script->code, script->length);
412     wscript->main = wscript->code + (script->main - script->code);
413
414     memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote));
415     memcpy(wscript->atomMap.vector, script->atomMap.vector,
416            wscript->atomMap.length * sizeof(JSAtom *));
417     if (JSScript::isValidOffset(script->objectsOffset)) {
418         memcpy(wscript->objects()->vector, script->objects()->vector,
419                wscript->objects()->length * sizeof(JSObject *));
420     }
421     if (JSScript::isValidOffset(script->regexpsOffset)) {
422         memcpy(wscript->regexps()->vector, script->regexps()->vector,
423                wscript->regexps()->length * sizeof(JSObject *));
424     }
425     if (JSScript::isValidOffset(script->trynotesOffset)) {
426         memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
427                wscript->trynotes()->length * sizeof(JSTryNote));
428     }
429     if (JSScript::isValidOffset(script->globalsOffset)) {
430         memcpy(wscript->globals()->vector, script->globals()->vector,
431                wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
432     }
433     if (script->nClosedArgs + script->nClosedVars != 0)
434         script->copyClosedSlotsTo(wscript);
435
436     if (script->bindings.hasUpvars()) {
437         JS_ASSERT(script->bindings.countUpvars() == wscript->upvars()->length);
438         memcpy(wscript->upvars()->vector, script->upvars()->vector,
439                script->bindings.countUpvars() * sizeof(uint32));
440     }
441
442     jsbytecode *pc = wscript->code;
443     while (*pc != JSOP_STOP) {
444         /* FIXME should copy JSOP_TRAP? */
445         JSOp op = js_GetOpcode(cx, wscript, pc);
446         const JSCodeSpec *cs = &js_CodeSpec[op];
447         ptrdiff_t oplen = cs->length;
448         if (oplen < 0)
449             oplen = js_GetVariableBytecodeLength(pc);
450
451         /*
452          * Rewrite JSOP_{GET,CALL}FCSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
453          * case where fun is an escaping flat closure. This works because the
454          * UPVAR and FCSLOT ops by design have the same format: an upvar index
455          * immediate operand.
456          */
457         switch (op) {
458           case JSOP_GETFCSLOT:      *pc = JSOP_GETUPVAR_DBG; break;
459           case JSOP_CALLFCSLOT:     *pc = JSOP_CALLUPVAR_DBG; break;
460           case JSOP_DEFFUN_FC:      *pc = JSOP_DEFFUN_DBGFC; break;
461           case JSOP_DEFLOCALFUN_FC: *pc = JSOP_DEFLOCALFUN_DBGFC; break;
462           case JSOP_LAMBDA_FC:      *pc = JSOP_LAMBDA_DBGFC; break;
463           default:;
464         }
465         pc += oplen;
466     }
467
468     /*
469      * Fill in the rest of wscript. This means if you add members to JSScript
470      * you must update this code. FIXME: factor into JSScript::clone method.
471      */
472     JS_ASSERT(wscript->getVersion() == script->getVersion());
473     wscript->nfixed = script->nfixed;
474     wscript->filename = script->filename;
475     wscript->lineno = script->lineno;
476     wscript->nslots = script->nslots;
477     wscript->staticLevel = script->staticLevel;
478     wscript->principals = script->principals;
479     wscript->noScriptRval = script->noScriptRval;
480     wscript->savedCallerFun = script->savedCallerFun;
481     wscript->hasSharps = script->hasSharps;
482     wscript->strictModeCode = script->strictModeCode;
483     wscript->compileAndGo = script->compileAndGo;
484     wscript->usesEval = script->usesEval;
485     wscript->usesArguments = script->usesArguments;
486     wscript->warnedAboutTwoArgumentEval = script->warnedAboutTwoArgumentEval;
487     if (wscript->principals)
488         JSPRINCIPALS_HOLD(cx, wscript->principals);
489 #ifdef CHECK_SCRIPT_OWNER
490     wscript->owner = script->owner;
491 #endif
492
493     wscript->bindings.clone(cx, &script->bindings);
494
495     /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
496     FUN_SET_KIND(wfun, JSFUN_INTERPRETED);
497     wfun->u.i.script = wscript;
498     return wfunobj;
499 }
500
501 static JSBool
502 ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
503 {
504     LeaveTrace(cx);
505
506     if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
507         return true;
508
509     if (JSID_IS_INT(id)) {
510         /*
511          * arg can exceed the number of arguments if a script changed the
512          * prototype to point to another Arguments object with a bigger argc.
513          */
514         uintN arg = uintN(JSID_TO_INT(id));
515         if (arg < obj->getArgsInitialLength()) {
516             JS_ASSERT(!obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE));
517             if (JSStackFrame *fp = (JSStackFrame *) obj->getPrivate())
518                 *vp = fp->canonicalActualArg(arg);
519             else
520                 *vp = obj->getArgsElement(arg);
521         }
522     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
523         if (!obj->isArgsLengthOverridden())
524             vp->setInt32(obj->getArgsInitialLength());
525     } else {
526         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
527         const Value &v = obj->getArgsCallee();
528         if (!v.isMagic(JS_ARGS_HOLE)) {
529             /*
530              * If this function or one in it needs upvars that reach above it
531              * in the scope chain, it must not be a null closure (it could be a
532              * flat closure, or an unoptimized closure -- the latter itself not
533              * necessarily heavyweight). Rather than wrap here, we simply throw
534              * to reduce code size and tell debugger users the truth instead of
535              * passing off a fibbing wrapper.
536              */
537             if (GET_FUNCTION_PRIVATE(cx, &v.toObject())->needsWrapper()) {
538                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
539                                      JSMSG_OPTIMIZED_CLOSURE_LEAK);
540                 return false;
541             }
542             *vp = v;
543         }
544     }
545     return true;
546 }
547
548 static JSBool
549 ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
550 {
551 #ifdef JS_TRACER
552     // To be able to set a property here on trace, we would have to make
553     // sure any updates also get written back to the trace native stack.
554     // For simplicity, we just leave trace, since this is presumably not
555     // a common operation.
556     LeaveTrace(cx);
557 #endif
558
559     if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
560         return true;
561
562     if (JSID_IS_INT(id)) {
563         uintN arg = uintN(JSID_TO_INT(id));
564         if (arg < obj->getArgsInitialLength()) {
565             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
566             if (fp) {
567                 JSScript *script = fp->functionScript();
568                 if (script->usesArguments)
569                     fp->canonicalActualArg(arg) = *vp;
570                 return true;
571             }
572         }
573     } else {
574         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
575                   JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
576     }
577
578     /*
579      * For simplicity we use delete/define to replace the property with one
580      * backed by the default Object getter and setter. Note that we rely on
581      * args_delProperty to clear the corresponding reserved slot so the GC can
582      * collect its value. Note also that we must define the property instead
583      * of setting it in case the user has changed the prototype to an object
584      * that has a setter for this id.
585      */
586     AutoValueRooter tvr(cx);
587     return js_DeleteProperty(cx, obj, id, tvr.addr(), false) &&
588            js_DefineProperty(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
589 }
590
591 static JSBool
592 args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
593              JSObject **objp)
594 {
595     JS_ASSERT(obj->isNormalArguments());
596
597     *objp = NULL;
598
599     uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
600     if (JSID_IS_INT(id)) {
601         uint32 arg = uint32(JSID_TO_INT(id));
602         if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
603             return true;
604
605         attrs |= JSPROP_ENUMERATE;
606     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
607         if (obj->isArgsLengthOverridden())
608             return true;
609     } else {
610         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
611             return true;
612
613         if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
614             return true;
615     }
616
617     Value undef = UndefinedValue();
618     if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
619         return JS_FALSE;
620
621     *objp = obj;
622     return true;
623 }
624
625 static JSBool
626 args_enumerate(JSContext *cx, JSObject *obj)
627 {
628     JS_ASSERT(obj->isNormalArguments());
629
630     /*
631      * Trigger reflection in args_resolve using a series of js_LookupProperty
632      * calls.
633      */
634     int argc = int(obj->getArgsInitialLength());
635     for (int i = -2; i != argc; i++) {
636         jsid id = (i == -2)
637                   ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
638                   : (i == -1)
639                   ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
640                   : INT_TO_JSID(i);
641
642         JSObject *pobj;
643         JSProperty *prop;
644         if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
645             return false;
646     }
647     return true;
648 }
649
650 static JSBool
651 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
652 {
653     LeaveTrace(cx);
654
655     if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
656         return true;
657
658     if (JSID_IS_INT(id)) {
659         /*
660          * arg can exceed the number of arguments if a script changed the
661          * prototype to point to another Arguments object with a bigger argc.
662          */
663         uintN arg = uintN(JSID_TO_INT(id));
664         if (arg < obj->getArgsInitialLength()) {
665             const Value &v = obj->getArgsElement(arg);
666             if (!v.isMagic(JS_ARGS_HOLE))
667                 *vp = v;
668         }
669     } else {
670         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
671         if (!obj->isArgsLengthOverridden())
672             vp->setInt32(obj->getArgsInitialLength());
673     }
674     return true;
675 }
676
677 static JSBool
678
679 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
680 {
681     if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
682         return true;
683
684     if (JSID_IS_INT(id)) {
685         uintN arg = uintN(JSID_TO_INT(id));
686         if (arg < obj->getArgsInitialLength()) {
687             obj->setArgsElement(arg, *vp);
688             return true;
689         }
690     } else {
691         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
692     }
693
694     /*
695      * For simplicity we use delete/set to replace the property with one
696      * backed by the default Object getter and setter. Note that we rely on
697      * args_delProperty to clear the corresponding reserved slot so the GC can
698      * collect its value.
699      */
700     AutoValueRooter tvr(cx);
701     return js_DeleteProperty(cx, obj, id, tvr.addr(), strict) &&
702            js_SetProperty(cx, obj, id, vp, strict);
703 }
704
705 static JSBool
706 strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
707 {
708     JS_ASSERT(obj->isStrictArguments());
709
710     *objp = NULL;
711
712     uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
713     PropertyOp getter = StrictArgGetter;
714     StrictPropertyOp setter = StrictArgSetter;
715
716     if (JSID_IS_INT(id)) {
717         uint32 arg = uint32(JSID_TO_INT(id));
718         if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
719             return true;
720
721         attrs |= JSPROP_ENUMERATE;
722     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
723         if (obj->isArgsLengthOverridden())
724             return true;
725     } else {
726         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
727             !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
728             return true;
729         }
730
731         attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
732         getter = CastAsPropertyOp(obj->getThrowTypeError());
733         setter = CastAsStrictPropertyOp(obj->getThrowTypeError());
734     }
735
736     Value undef = UndefinedValue();
737     if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
738         return false;
739
740     *objp = obj;
741     return true;
742 }
743
744 static JSBool
745 strictargs_enumerate(JSContext *cx, JSObject *obj)
746 {
747     JS_ASSERT(obj->isStrictArguments());
748
749     /*
750      * Trigger reflection in strictargs_resolve using a series of
751      * js_LookupProperty calls.
752      */
753     JSObject *pobj;
754     JSProperty *prop;
755
756     // length
757     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
758         return false;
759
760     // callee
761     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
762         return false;
763
764     // caller
765     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
766         return false;
767
768     for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
769         if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
770             return false;
771     }
772
773     return true;
774 }
775
776 static void
777 args_finalize(JSContext *cx, JSObject *obj)
778 {
779     cx->free((void *) obj->getArgsData());
780 }
781
782 /*
783  * If a generator's arguments or call object escapes, and the generator frame
784  * is not executing, the generator object needs to be marked because it is not
785  * otherwise reachable. An executing generator is rooted by its invocation.  To
786  * distinguish the two cases (which imply different access paths to the
787  * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
788  * set on the JSStackFrame kept in the generator object's JSGenerator.
789  */
790 static inline void
791 MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
792 {
793 #if JS_HAS_GENERATORS
794     JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
795     if (fp && fp->isFloatingGenerator()) {
796         JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
797         MarkObject(trc, *genobj, "generator object");
798     }
799 #endif
800 }
801
802 static void
803 args_trace(JSTracer *trc, JSObject *obj)
804 {
805     JS_ASSERT(obj->isArguments());
806     if (obj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
807         JS_ASSERT(!obj->isStrictArguments());
808         return;
809     }
810
811     ArgumentsData *data = obj->getArgsData();
812     if (data->callee.isObject())
813         MarkObject(trc, data->callee.toObject(), js_callee_str);
814     MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str);
815
816     MaybeMarkGenerator(trc, obj);
817 }
818
819 /*
820  * The Arguments classes aren't initialized via js_InitClass, because arguments
821  * objects have the initial value of Object.prototype as their [[Prototype]].
822  * However, Object.prototype.toString.call(arguments) === "[object Arguments]"
823  * per ES5 (although not ES3), so the class name is "Arguments" rather than
824  * "Object".
825  *
826  * The JSClass functions below collaborate to lazily reflect and synchronize
827  * actual argument values, argument count, and callee function object stored
828  * in a JSStackFrame with their corresponding property values in the frame's
829  * arguments object.
830  */
831 Class js_ArgumentsClass = {
832     "Arguments",
833     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
834     JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) |
835     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
836     PropertyStub,         /* addProperty */
837     args_delProperty,
838     PropertyStub,         /* getProperty */
839     StrictPropertyStub,   /* setProperty */
840     args_enumerate,
841     (JSResolveOp) args_resolve,
842     ConvertStub,
843     args_finalize,        /* finalize   */
844     NULL,                 /* reserved0   */
845     NULL,                 /* checkAccess */
846     NULL,                 /* call        */
847     NULL,                 /* construct   */
848     NULL,                 /* xdrObject   */
849     NULL,                 /* hasInstance */
850     JS_CLASS_TRACE(args_trace)
851 };
852
853 namespace js {
854
855 /*
856  * Strict mode arguments is significantly less magical than non-strict mode
857  * arguments, so it is represented by a different class while sharing some
858  * functionality.
859  */
860 Class StrictArgumentsClass = {
861     "Arguments",
862     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
863     JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) |
864     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
865     PropertyStub,         /* addProperty */
866     args_delProperty,
867     PropertyStub,         /* getProperty */
868     StrictPropertyStub,   /* setProperty */
869     strictargs_enumerate,
870     reinterpret_cast<JSResolveOp>(strictargs_resolve),
871     ConvertStub,
872     args_finalize,        /* finalize   */
873     NULL,                 /* reserved0   */
874     NULL,                 /* checkAccess */
875     NULL,                 /* call        */
876     NULL,                 /* construct   */
877     NULL,                 /* xdrObject   */
878     NULL,                 /* hasInstance */
879     JS_CLASS_TRACE(args_trace)
880 };
881
882 }
883
884 /*
885  * A Declarative Environment object stores its active JSStackFrame pointer in
886  * its private slot, just as Call and Arguments objects do.
887  */
888 Class js_DeclEnvClass = {
889     js_Object_str,
890     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
891     PropertyStub,         /* addProperty */
892     PropertyStub,         /* delProperty */
893     PropertyStub,         /* getProperty */
894     StrictPropertyStub,   /* setProperty */
895     EnumerateStub,
896     ResolveStub,
897     ConvertStub
898 };
899
900 static JSBool
901 CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp)
902 {
903     JS_ASSERT(obj->isCall() || obj->getClass() == &js_DeclEnvClass);
904
905     const Value &v = *vp;
906
907     JSObject *funobj;
908     if (IsFunctionObject(v, &funobj)) {
909         JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
910
911         /*
912          * Any escaping null or flat closure that reaches above itself or
913          * contains nested functions that reach above it must be wrapped.
914          * We can wrap only when this Call or Declarative Environment obj
915          * still has an active stack frame associated with it.
916          */
917         if (fun->needsWrapper()) {
918             LeaveTrace(cx);
919
920             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
921             if (fp) {
922                 JSObject *wrapper = WrapEscapingClosure(cx, fp, fun);
923                 if (!wrapper)
924                     return false;
925                 vp->setObject(*wrapper);
926                 return true;
927             }
928
929             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
930                                  JSMSG_OPTIMIZED_CLOSURE_LEAK);
931             return false;
932         }
933     }
934     return true;
935 }
936
937 static JSBool
938 CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
939 {
940     return CheckForEscapingClosure(cx, obj, vp);
941 }
942
943 namespace js {
944
945 /*
946  * Construct a call object for the given bindings.  The callee is the function
947  * on behalf of which the call object is being created.
948  */
949 JSObject *
950 NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject *callee)
951 {
952     size_t argsVars = bindings->countArgsAndVars();
953     size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
954     gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
955
956     JSObject *callobj = js_NewGCObject(cx, kind);
957     if (!callobj)
958         return NULL;
959
960     /* Init immediately to avoid GC seeing a half-init'ed object. */
961     callobj->init(cx, &js_CallClass, NULL, &scopeChain, NULL, false);
962     callobj->setMap(bindings->lastShape());
963
964     /* This must come after callobj->lastProp has been set. */
965     if (!callobj->ensureInstanceReservedSlots(cx, argsVars))
966         return NULL;
967
968 #ifdef DEBUG
969     for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) {
970         const Shape &s = r.front();
971         if (s.slot != SHAPE_INVALID_SLOT) {
972             JS_ASSERT(s.slot + 1 == callobj->slotSpan());
973             break;
974         }
975     }
976 #endif
977
978     callobj->setCallObjCallee(callee);
979     return callobj;
980 }
981
982 } // namespace js
983
984 static inline JSObject *
985 NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
986 {
987     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
988     if (!envobj)
989         return NULL;
990
991     envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
992     envobj->setMap(cx->compartment->emptyDeclEnvShape);
993     return envobj;
994 }
995
996 JSObject *
997 js_GetCallObject(JSContext *cx, JSStackFrame *fp)
998 {
999     /* Create a call object for fp only if it lacks one. */
1000     JS_ASSERT(fp->isFunctionFrame());
1001     if (fp->hasCallObj())
1002         return &fp->callObj();
1003
1004 #ifdef DEBUG
1005     /* A call object should be a frame's outermost scope chain element.  */
1006     Class *clasp = fp->scopeChain().getClass();
1007     if (clasp == &js_WithClass || clasp == &js_BlockClass)
1008         JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
1009     else if (clasp == &js_CallClass)
1010         JS_ASSERT(fp->scopeChain().getPrivate() != fp);
1011 #endif
1012
1013     /*
1014      * Create the call object, using the frame's enclosing scope as its
1015      * parent, and link the call to its stack frame. For a named function
1016      * expression Call's parent points to an environment object holding
1017      * function's name.
1018      */
1019     JSAtom *lambdaName =
1020         (fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL;
1021     if (lambdaName) {
1022         JSObject *envobj = NewDeclEnvObject(cx, fp);
1023         if (!envobj)
1024             return NULL;
1025
1026         /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
1027         fp->setScopeChainNoCallObj(*envobj);
1028         if (!js_DefineNativeProperty(cx, &fp->scopeChain(), ATOM_TO_JSID(lambdaName),
1029                                      ObjectValue(fp->callee()),
1030                                      CalleeGetter, NULL,
1031                                      JSPROP_PERMANENT | JSPROP_READONLY,
1032                                      0, 0, NULL)) {
1033             return NULL;
1034         }
1035     }
1036
1037     JSObject *callobj =
1038         NewCallObject(cx, &fp->fun()->script()->bindings, fp->scopeChain(), &fp->callee());
1039     if (!callobj)
1040         return NULL;
1041
1042     callobj->setPrivate(fp);
1043     JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
1044
1045     /*
1046      * Push callobj on the top of the scope chain, and make it the
1047      * variables object.
1048      */
1049     fp->setScopeChainAndCallObj(*callobj);
1050     return callobj;
1051 }
1052
1053 JSObject * JS_FASTCALL
1054 js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
1055 {
1056     JS_ASSERT(!js_IsNamedLambda(fun));
1057     JS_ASSERT(scopeChain);
1058     JS_ASSERT(callee);
1059     return NewCallObject(cx, &fun->script()->bindings, *scopeChain, callee);
1060 }
1061
1062 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
1063                      0, nanojit::ACCSET_STORE_ANY)
1064
1065 inline static void
1066 CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
1067 {
1068     JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
1069     Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
1070     memcpy(base, argv, nargs * sizeof(Value));
1071     memcpy(base + nargs, slots, nvars * sizeof(Value));
1072 }
1073
1074 void
1075 js_PutCallObject(JSContext *cx, JSStackFrame *fp)
1076 {
1077     JSObject &callobj = fp->callObj();
1078
1079     /*
1080      * Strict mode eval frames have Call objects to put.  Normal eval frames
1081      * never put a Call object.
1082      */
1083     JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval());
1084
1085     /* Get the arguments object to snapshot fp's actual argument values. */
1086     if (fp->hasArgsObj()) {
1087         if (!fp->hasOverriddenArgs())
1088             callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
1089         js_PutArgsObject(cx, fp);
1090     }
1091
1092     JSScript *script = fp->script();
1093     Bindings &bindings = script->bindings;
1094
1095     if (callobj.callIsForEval()) {
1096         JS_ASSERT(script->strictModeCode);
1097         JS_ASSERT(bindings.countArgs() == 0);
1098
1099         /* This could be optimized as below, but keep it simple for now. */
1100         CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
1101     } else {
1102         JSFunction *fun = fp->fun();
1103         JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
1104         JS_ASSERT(script == fun->script());
1105
1106         uintN n = bindings.countArgsAndVars();
1107         if (n > 0) {
1108             JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
1109
1110             uint32 nvars = bindings.countVars();
1111             uint32 nargs = bindings.countArgs();
1112             JS_ASSERT(fun->nargs == nargs);
1113             JS_ASSERT(nvars + nargs == n);
1114
1115             JSScript *script = fun->script();
1116             if (script->usesEval
1117 #ifdef JS_METHODJIT
1118                 || script->debugMode
1119 #endif
1120                 ) {
1121                 CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
1122             } else {
1123                 /*
1124                  * For each arg & var that is closed over, copy it from the stack
1125                  * into the call object.
1126                  */
1127                 uint32 nclosed = script->nClosedArgs;
1128                 for (uint32 i = 0; i < nclosed; i++) {
1129                     uint32 e = script->getClosedArg(i);
1130                     callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
1131                 }
1132
1133                 nclosed = script->nClosedVars;
1134                 for (uint32 i = 0; i < nclosed; i++) {
1135                     uint32 e = script->getClosedVar(i);
1136                     callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
1137                 }
1138             }
1139         }
1140
1141         /* Clear private pointers to fp, which is about to go away (js_Invoke). */
1142         if (js_IsNamedLambda(fun)) {
1143             JSObject *env = callobj.getParent();
1144
1145             JS_ASSERT(env->getClass() == &js_DeclEnvClass);
1146             JS_ASSERT(env->getPrivate() == fp);
1147             env->setPrivate(NULL);
1148         }
1149     }
1150
1151     callobj.setPrivate(NULL);
1152     fp->clearCallObj();
1153 }
1154
1155 JSBool JS_FASTCALL
1156 js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv,
1157                         uint32 nvars, Value *slots)
1158 {
1159     JS_ASSERT(callobj->isCall());
1160     JS_ASSERT(!callobj->getPrivate());
1161
1162     uintN n = nargs + nvars;
1163     if (n != 0)
1164         CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
1165
1166     return true;
1167 }
1168
1169 JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR,
1170                      UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
1171
1172 namespace js {
1173
1174 static JSBool
1175 GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1176 {
1177     JSStackFrame *fp = obj->maybeCallObjStackFrame();
1178     if (fp && !fp->hasOverriddenArgs()) {
1179         JSObject *argsobj = js_GetArgsObject(cx, fp);
1180         if (!argsobj)
1181             return false;
1182         vp->setObject(*argsobj);
1183     } else {
1184         *vp = obj->getCallObjArguments();
1185     }
1186     return true;
1187 }
1188
1189 static JSBool
1190 SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1191 {
1192     if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1193         fp->setOverriddenArgs();
1194     obj->setCallObjArguments(*vp);
1195     return true;
1196 }
1197
1198 JSBool
1199 GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1200 {
1201     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1202     uintN i = (uint16) JSID_TO_INT(id);
1203
1204     if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1205         *vp = fp->formalArg(i);
1206     else
1207         *vp = obj->callObjArg(i);
1208     return true;
1209 }
1210
1211 JSBool
1212 SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1213 {
1214     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1215     uintN i = (uint16) JSID_TO_INT(id);
1216
1217     Value *argp;
1218     if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1219         argp = &fp->formalArg(i);
1220     else
1221         argp = &obj->callObjArg(i);
1222
1223     GC_POKE(cx, *argp);
1224     *argp = *vp;
1225     return true;
1226 }
1227
1228 JSBool
1229 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1230 {
1231     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1232     uintN i = (uint16) JSID_TO_INT(id);
1233
1234     *vp = obj->getCallObjCallee()->getFlatClosureUpvar(i);
1235     return true;
1236 }
1237
1238 JSBool
1239 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1240 {
1241     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1242     uintN i = (uint16) JSID_TO_INT(id);
1243
1244     Value *up = &obj->getCallObjCallee()->getFlatClosureUpvar(i);
1245
1246     GC_POKE(cx, *up);
1247     *up = *vp;
1248     return true;
1249 }
1250
1251 JSBool
1252 GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1253 {
1254     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1255     uintN i = (uint16) JSID_TO_INT(id);
1256
1257     if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1258         *vp = fp->varSlot(i);
1259     else
1260         *vp = obj->callObjVar(i);
1261
1262     return true;
1263 }
1264
1265 JSBool
1266 GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1267 {
1268     if (!GetCallVar(cx, obj, id, vp))
1269         return false;
1270
1271     return CheckForEscapingClosure(cx, obj, vp);
1272 }
1273
1274 JSBool
1275 SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1276 {
1277     JS_ASSERT(obj->isCall());
1278
1279     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1280     uintN i = (uint16) JSID_TO_INT(id);
1281
1282     /*
1283      * As documented in TraceRecorder::attemptTreeCall(), when recording an
1284      * inner tree call, the recorder assumes the inner tree does not mutate
1285      * any tracked upvars. The abort here is a pessimistic precaution against
1286      * bug 620662, where an inner tree setting a closed stack variable in an
1287      * outer tree is illegal, and runtime would fall off trace.
1288      */
1289 #ifdef JS_TRACER
1290     if (JS_ON_TRACE(cx)) {
1291         TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
1292         if (tm->recorder && tm->tracecx)
1293             AbortRecording(cx, "upvar write in nested tree");
1294     }
1295 #endif
1296
1297     Value *varp;
1298     if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1299         varp = &fp->varSlot(i);
1300     else
1301         varp = &obj->callObjVar(i);
1302
1303     GC_POKE(cx, *varp);
1304     *varp = *vp;
1305     return true;
1306 }
1307
1308 } // namespace js
1309
1310 #if JS_TRACER
1311 JSBool JS_FASTCALL
1312 js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
1313 {
1314     Value argcopy = ValueArgToConstRef(arg);
1315     return SetCallArg(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy);
1316 }
1317 JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, VALUE, 0,
1318                      nanojit::ACCSET_STORE_ANY)
1319
1320 JSBool JS_FASTCALL
1321 js_SetCallVar(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
1322 {
1323     Value argcopy = ValueArgToConstRef(arg);
1324     return SetCallVar(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy);
1325 }
1326 JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0,
1327                      nanojit::ACCSET_STORE_ANY)
1328 #endif
1329
1330 static JSBool
1331 call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
1332              JSObject **objp)
1333 {
1334     JS_ASSERT(obj->isCall());
1335     JS_ASSERT(!obj->getProto());
1336
1337     if (!JSID_IS_ATOM(id))
1338         return true;
1339
1340     JSObject *callee = obj->getCallObjCallee();
1341 #ifdef DEBUG
1342     if (callee) {
1343         JSScript *script = callee->getFunctionPrivate()->script();
1344         JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
1345     }
1346 #endif
1347
1348     /*
1349      * Resolve arguments so that we never store a particular Call object's
1350      * arguments object reference in a Call prototype's |arguments| slot.
1351      *
1352      * Include JSPROP_ENUMERATE for consistency with all other Call object
1353      * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
1354      * rebinding-Call-property logic.
1355      */
1356     if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
1357         if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
1358                                      GetCallArguments, SetCallArguments,
1359                                      JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
1360                                      0, 0, NULL, JSDNP_DONT_PURGE)) {
1361             return false;
1362         }
1363         *objp = obj;
1364         return true;
1365     }
1366
1367     /* Control flow reaches here only if id was not resolved. */
1368     return true;
1369 }
1370
1371 static void
1372 call_trace(JSTracer *trc, JSObject *obj)
1373 {
1374     JS_ASSERT(obj->isCall());
1375     if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) {
1376         /*
1377          * FIXME: Hide copies of stack values rooted by fp from the Cycle
1378          * Collector, which currently lacks a non-stub Unlink implementation
1379          * for JS objects (including Call objects), so is unable to collect
1380          * cycles involving Call objects whose frames are active without this
1381          * hiding hack.
1382          */
1383         uintN first = JSObject::CALL_RESERVED_SLOTS;
1384         uintN count = fp->script()->bindings.countArgsAndVars();
1385
1386         JS_ASSERT(obj->numSlots() >= first + count);
1387         SetValueRangeToUndefined(obj->getSlots() + first, count);
1388     }
1389
1390     MaybeMarkGenerator(trc, obj);
1391 }
1392
1393 JS_PUBLIC_DATA(Class) js_CallClass = {
1394     "Call",
1395     JSCLASS_HAS_PRIVATE |
1396     JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
1397     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
1398     PropertyStub,         /* addProperty */
1399     PropertyStub,         /* delProperty */
1400     PropertyStub,         /* getProperty */
1401     StrictPropertyStub,   /* setProperty */
1402     JS_EnumerateStub,
1403     (JSResolveOp)call_resolve,
1404     NULL,                 /* convert: Leave it NULL so we notice if calls ever escape */
1405     NULL,                 /* finalize */
1406     NULL,                 /* reserved0   */
1407     NULL,                 /* checkAccess */
1408     NULL,                 /* call        */
1409     NULL,                 /* construct   */
1410     NULL,                 /* xdrObject   */
1411     NULL,                 /* hasInstance */
1412     JS_CLASS_TRACE(call_trace)
1413 };
1414
1415 bool
1416 JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
1417 {
1418     if (!isFunctionFrame()) {
1419         vp->setUndefined();
1420         return true;
1421     }
1422
1423     JSFunction *fun = this->fun();
1424
1425     /*
1426      * See the equivalent condition in ArgGetter for the 'callee' id case, but
1427      * note that here we do not want to throw, since this escape can happen via
1428      * a foo.caller reference alone, without any debugger or indirect eval. And
1429      * alas, it seems foo.caller is still used on the Web.
1430      */
1431     if (fun->needsWrapper()) {
1432         JSObject *wrapper = WrapEscapingClosure(cx, this, fun);
1433         if (!wrapper)
1434             return false;
1435         vp->setObject(*wrapper);
1436         return true;
1437     }
1438
1439     JSObject &funobj = callee();
1440     vp->setObject(funobj);
1441
1442     /*
1443      * Check for an escape attempt by a joined function object, which must go
1444      * through the frame's |this| object's method read barrier for the method
1445      * atom by which it was uniquely associated with a property.
1446      */
1447     const Value &thisv = functionThis();
1448     if (thisv.isObject()) {
1449         JS_ASSERT(funobj.getFunctionPrivate() == fun);
1450
1451         if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) {
1452             JSObject *thisp = &thisv.toObject();
1453             JSObject *first_barriered_thisp = NULL;
1454
1455             do {
1456                 /*
1457                  * While a non-native object is responsible for handling its
1458                  * entire prototype chain, notable non-natives including dense
1459                  * and typed arrays have native prototypes, so keep going.
1460                  */
1461                 if (!thisp->isNative())
1462                     continue;
1463
1464                 if (thisp->hasMethodBarrier()) {
1465                     const Shape *shape = thisp->nativeLookup(ATOM_TO_JSID(fun->methodAtom()));
1466                     if (shape) {
1467                         /*
1468                          * Two cases follow: the method barrier was not crossed
1469                          * yet, so we cross it here; the method barrier *was*
1470                          * crossed but after the call, in which case we fetch
1471                          * and validate the cloned (unjoined) funobj from the
1472                          * method property's slot.
1473                          *
1474                          * In either case we must allow for the method property
1475                          * to have been replaced, or its value overwritten.
1476                          */
1477                         if (shape->isMethod() && &shape->methodObject() == &funobj) {
1478                             if (!thisp->methodReadBarrier(cx, *shape, vp))
1479                                 return false;
1480                             calleeValue().setObject(vp->toObject());
1481                             return true;
1482                         }
1483
1484                         if (shape->hasSlot()) {
1485                             Value v = thisp->getSlot(shape->slot);
1486                             JSObject *clone;
1487
1488                             if (IsFunctionObject(v, &clone) &&
1489                                 GET_FUNCTION_PRIVATE(cx, clone) == fun &&
1490                                 clone->hasMethodObj(*thisp)) {
1491                                 JS_ASSERT(clone != &funobj);
1492                                 *vp = v;
1493                                 calleeValue().setObject(*clone);
1494                                 return true;
1495                             }
1496                         }
1497                     }
1498
1499                     if (!first_barriered_thisp)
1500                         first_barriered_thisp = thisp;
1501                 }
1502             } while ((thisp = thisp->getProto()) != NULL);
1503
1504             if (!first_barriered_thisp)
1505                 return true;
1506
1507             /*
1508              * At this point, we couldn't find an already-existing clone (or
1509              * force to exist a fresh clone) created via thisp's method read
1510              * barrier, so we must clone fun and store it in fp's callee to
1511              * avoid re-cloning upon repeated foo.caller access.
1512              *
1513              * This must mean the code in js_DeleteProperty could not find this
1514              * stack frame on the stack when the method was deleted. We've lost
1515              * track of the method, so we associate it with the first barriered
1516              * object found starting from thisp on the prototype chain.
1517              */
1518             JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent());
1519             if (!newfunobj)
1520                 return false;
1521             newfunobj->setMethodObj(*first_barriered_thisp);
1522             calleeValue().setObject(*newfunobj);
1523             vp->setObject(*newfunobj);
1524             return true;
1525         }
1526     }
1527
1528     return true;
1529 }
1530
1531 /* Generic function tinyids. */
1532 enum {
1533     FUN_ARGUMENTS   = -1,       /* predefined arguments local variable */
1534     FUN_LENGTH      = -2,       /* number of actual args, arity if inactive */
1535     FUN_ARITY       = -3,       /* number of formal parameters; desired argc */
1536     FUN_NAME        = -4,       /* function name, "" if anonymous */
1537     FUN_CALLER      = -5        /* Function.prototype.caller, backward compat */
1538 };
1539
1540 static JSBool
1541 fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1542 {
1543     if (!JSID_IS_INT(id))
1544         return true;
1545
1546     jsint slot = JSID_TO_INT(id);
1547
1548     /*
1549      * Loop because getter and setter can be delegated from another class,
1550      * but loop only for FUN_LENGTH because we must pretend that f.length
1551      * is in each function instance f, per ECMA-262, instead of only in the
1552      * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1553      * to make it appear so).
1554      *
1555      * This code couples tightly to the attributes for lazyFunctionDataProps[]
1556      * and poisonPillProps[] initializers below, and to js_SetProperty and
1557      * js_HasOwnProperty.
1558      *
1559      * It's important to allow delegating objects, even though they inherit
1560      * this getter (fun_getProperty), to override arguments, arity, caller,
1561      * and name.  If we didn't return early for slot != FUN_LENGTH, we would
1562      * clobber *vp with the native property value, instead of letting script
1563      * override that value in delegating objects.
1564      *
1565      * Note how that clobbering is what simulates JSPROP_READONLY for all of
1566      * the non-standard properties when the directly addressed object (obj)
1567      * is a function object (i.e., when this loop does not iterate).
1568      */
1569     JSFunction *fun;
1570     while (!(fun = (JSFunction *)
1571                    GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
1572         if (slot != FUN_LENGTH)
1573             return true;
1574         obj = obj->getProto();
1575         if (!obj)
1576             return true;
1577     }
1578
1579     /* Find fun's top-most activation record. */
1580     JSStackFrame *fp;
1581     for (fp = js_GetTopStackFrame(cx);
1582          fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
1583          fp = fp->prev()) {
1584         continue;
1585     }
1586
1587     switch (slot) {
1588       case FUN_ARGUMENTS:
1589         /* Warn if strict about f.arguments or equivalent unqualified uses. */
1590         if (!JS_ReportErrorFlagsAndNumber(cx,
1591                                           JSREPORT_WARNING | JSREPORT_STRICT,
1592                                           js_GetErrorMessage, NULL,
1593                                           JSMSG_DEPRECATED_USAGE,
1594                                           js_arguments_str)) {
1595             return false;
1596         }
1597         if (fp) {
1598             if (!js_GetArgsValue(cx, fp, vp))
1599                 return false;
1600         } else {
1601             vp->setNull();
1602         }
1603         break;
1604
1605       case FUN_LENGTH:
1606       case FUN_ARITY:
1607         vp->setInt32(fun->nargs);
1608         break;
1609
1610       case FUN_NAME:
1611         vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom)
1612                                 : cx->runtime->emptyString);
1613         break;
1614
1615       case FUN_CALLER:
1616         vp->setNull();
1617         if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
1618             return false;
1619
1620         if (vp->isObject()) {
1621             JSObject &caller = vp->toObject();
1622
1623             /* Censor the caller if it is from another compartment. */
1624             if (caller.getCompartment() != cx->compartment) {
1625                 vp->setNull();
1626             } else if (caller.isFunction()) {
1627                 JSFunction *callerFun = caller.getFunctionPrivate();
1628                 if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
1629                     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
1630                                                  JSMSG_CALLER_IS_STRICT);
1631                     return false;
1632                 }
1633             }
1634         }
1635         break;
1636
1637       default:
1638         /* XXX fun[0] and fun.arguments[0] are equivalent. */
1639         if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
1640             *vp = fp->formalArg(slot);
1641         break;
1642     }
1643
1644     return true;
1645 }
1646
1647 struct LazyFunctionDataProp {
1648     uint16      atomOffset;
1649     int8        tinyid;
1650     uint8       attrs;
1651 };
1652
1653 struct PoisonPillProp {
1654     uint16       atomOffset;
1655     int8         tinyid;
1656 };
1657
1658 /* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
1659
1660 static const LazyFunctionDataProp lazyFunctionDataProps[] = {
1661     {ATOM_OFFSET(arity),     FUN_ARITY,      JSPROP_PERMANENT|JSPROP_READONLY},
1662     {ATOM_OFFSET(name),      FUN_NAME,       JSPROP_PERMANENT|JSPROP_READONLY},
1663 };
1664
1665 /* Properties censored into [[ThrowTypeError]] in strict mode. */
1666 static const PoisonPillProp poisonPillProps[] = {
1667     {ATOM_OFFSET(arguments), FUN_ARGUMENTS },
1668     {ATOM_OFFSET(caller),    FUN_CALLER    },
1669 };
1670
1671 static JSBool
1672 fun_enumerate(JSContext *cx, JSObject *obj)
1673 {
1674     JS_ASSERT(obj->isFunction());
1675
1676     jsid id;
1677     bool found;
1678
1679     if (!obj->isBoundFunction()) {
1680         id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1681         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
1682             return false;
1683     }
1684
1685     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
1686     if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
1687         return false;
1688
1689     for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
1690         const LazyFunctionDataProp &lfp = lazyFunctionDataProps[i];
1691         id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, lfp.atomOffset));
1692         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
1693             return false;
1694     }
1695
1696     for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
1697         const PoisonPillProp &p = poisonPillProps[i];
1698         id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, p.atomOffset));
1699         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
1700             return false;
1701     }
1702
1703     return true;
1704 }
1705
1706 static JSObject *
1707 ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
1708 {
1709 #ifdef DEBUG
1710     JSFunction *fun = obj->getFunctionPrivate();
1711     JS_ASSERT(fun->isInterpreted());
1712     JS_ASSERT(!fun->isFunctionPrototype());
1713 #endif
1714
1715     /*
1716      * Assert that fun is not a compiler-created function object, which
1717      * must never leak to script or embedding code and then be mutated.
1718      * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
1719      */
1720     JS_ASSERT(!IsInternalFunctionObject(obj));
1721     JS_ASSERT(!obj->isBoundFunction());
1722
1723     /*
1724      * Make the prototype object an instance of Object with the same parent
1725      * as the function object itself.
1726      */
1727     JSObject *parent = obj->getParent();
1728     JSObject *proto;
1729     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
1730         return NULL;
1731     proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent);
1732     if (!proto)
1733         return NULL;
1734
1735     /*
1736      * ECMA (15.3.5.2) says that a user-defined function's .prototype property
1737      * is non-configurable, non-enumerable, and (initially) writable. Hence
1738      * JSPROP_PERMANENT below. By contrast, the built-in constructors, such as
1739      * Object (15.2.3.1) and Function (15.3.3.1), have non-writable
1740      * .prototype properties. Those are eagerly defined, with attributes
1741      * JSPROP_PERMANENT | JSPROP_READONLY, in js_InitClass.
1742      */
1743     if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT))
1744         return NULL;
1745     return proto;
1746 }
1747
1748 static JSBool
1749 fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
1750             JSObject **objp)
1751 {
1752     if (!JSID_IS_ATOM(id))
1753         return true;
1754
1755     JSFunction *fun = obj->getFunctionPrivate();
1756
1757     if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
1758         /*
1759          * Native or "built-in" functions do not have a .prototype property per
1760          * ECMA-262 (all editions). Built-in constructor functions, e.g. Object
1761          * and Function to name two conspicuous examples, do have a .prototype
1762          * property, but it is created eagerly by js_InitClass (jsobj.cpp).
1763          *
1764          * ES5 15.3.4: the non-native function object named Function.prototype
1765          * must not have a .prototype property.
1766          *
1767          * ES5 15.3.4.5: bound functions don't have a prototype property. The
1768          * isNative() test covers this case because bound functions are native
1769          * functions by definition/construction.
1770          */
1771         if (fun->isNative() || fun->isFunctionPrototype())
1772             return true;
1773
1774         if (!ResolveInterpretedFunctionPrototype(cx, obj))
1775             return false;
1776         *objp = obj;
1777         return true;
1778     }
1779
1780     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
1781         JS_ASSERT(!IsInternalFunctionObject(obj));
1782         if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
1783                                      PropertyStub, StrictPropertyStub,
1784                                      JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
1785             return false;
1786         }
1787         *objp = obj;
1788         return true;
1789     }
1790
1791     for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
1792         const LazyFunctionDataProp *lfp = &lazyFunctionDataProps[i];
1793
1794         if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset))) {
1795             JS_ASSERT(!IsInternalFunctionObject(obj));
1796
1797             if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
1798                                          fun_getProperty, StrictPropertyStub,
1799                                          lfp->attrs, Shape::HAS_SHORTID,
1800                                          lfp->tinyid, NULL)) {
1801                 return false;
1802             }
1803             *objp = obj;
1804             return true;
1805         }
1806     }
1807
1808     for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
1809         const PoisonPillProp &p = poisonPillProps[i];
1810
1811         if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, p.atomOffset))) {
1812             JS_ASSERT(!IsInternalFunctionObject(obj));
1813
1814             PropertyOp getter;
1815             StrictPropertyOp setter;
1816             uintN attrs = JSPROP_PERMANENT;
1817             if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) {
1818                 JSObject *throwTypeError = obj->getThrowTypeError();
1819
1820                 getter = CastAsPropertyOp(throwTypeError);
1821                 setter = CastAsStrictPropertyOp(throwTypeError);
1822                 attrs |= JSPROP_GETTER | JSPROP_SETTER;
1823             } else {
1824                 getter = fun_getProperty;
1825                 setter = StrictPropertyStub;
1826             }
1827
1828             if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
1829                                          getter, setter,
1830                                          attrs, Shape::HAS_SHORTID,
1831                                          p.tinyid, NULL)) {
1832                 return false;
1833             }
1834             *objp = obj;
1835             return true;
1836         }
1837     }
1838
1839     return true;
1840 }
1841
1842 #if JS_HAS_XDR
1843
1844 /* XXX store parent and proto, if defined */
1845 JSBool
1846 js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
1847 {
1848     JSContext *cx;
1849     JSFunction *fun;
1850     uint32 firstword;           /* flag telling whether fun->atom is non-null,
1851                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
1852                                    and 14 bits reserved for future use */
1853     uint32 flagsword;           /* word for argument count and fun->flags */
1854
1855     cx = xdr->cx;
1856     if (xdr->mode == JSXDR_ENCODE) {
1857         fun = GET_FUNCTION_PRIVATE(cx, *objp);
1858         if (!FUN_INTERPRETED(fun)) {
1859             JSAutoByteString funNameBytes;
1860             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
1861                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
1862                                      name);
1863             }
1864             return false;
1865         }
1866         if (fun->u.i.wrapper) {
1867             JSAutoByteString funNameBytes;
1868             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes))
1869                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, name);
1870             return false;
1871         }
1872         JS_ASSERT((fun->u.i.wrapper & ~1U) == 0);
1873         firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom;
1874         flagsword = (fun->nargs << 16) | fun->flags;
1875     } else {
1876         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1877         if (!fun)
1878             return false;
1879         FUN_OBJECT(fun)->clearParent();
1880         FUN_OBJECT(fun)->clearProto();
1881     }
1882
1883     AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
1884
1885     if (!JS_XDRUint32(xdr, &firstword))
1886         return false;
1887     if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
1888         return false;
1889     if (!JS_XDRUint32(xdr, &flagsword))
1890         return false;
1891
1892     if (xdr->mode == JSXDR_DECODE) {
1893         fun->nargs = flagsword >> 16;
1894         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
1895         fun->flags = uint16(flagsword);
1896         fun->u.i.skipmin = uint16(firstword >> 2);
1897         fun->u.i.wrapper = JSPackedBool((firstword >> 1) & 1);
1898     }
1899
1900     if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
1901         return false;
1902
1903     if (xdr->mode == JSXDR_DECODE) {
1904         *objp = FUN_OBJECT(fun);
1905 #ifdef CHECK_SCRIPT_OWNER
1906         fun->script()->owner = NULL;
1907 #endif
1908         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
1909         js_CallNewScriptHook(cx, fun->script(), fun);
1910     }
1911
1912     return true;
1913 }
1914
1915 #else  /* !JS_HAS_XDR */
1916
1917 #define js_XDRFunctionObject NULL
1918
1919 #endif /* !JS_HAS_XDR */
1920
1921 /*
1922  * [[HasInstance]] internal method for Function objects: fetch the .prototype
1923  * property of its 'this' parameter, and walks the prototype chain of v (only
1924  * if v is an object) returning true if .prototype is found.
1925  */
1926 static JSBool
1927 fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
1928 {
1929     while (obj->isFunction()) {
1930         if (!obj->isBoundFunction())
1931             break;
1932         obj = obj->getBoundFunctionTarget();
1933     }
1934
1935     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1936     Value pval;
1937     if (!obj->getProperty(cx, id, &pval))
1938         return JS_FALSE;
1939
1940     if (pval.isPrimitive()) {
1941         /*
1942          * Throw a runtime error if instanceof is called on a function that
1943          * has a non-object as its .prototype value.
1944          */
1945         js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
1946         return JS_FALSE;
1947     }
1948
1949     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
1950     return JS_TRUE;
1951 }
1952
1953 static void
1954 fun_trace(JSTracer *trc, JSObject *obj)
1955 {
1956     /* A newborn function object may have a not yet initialized private slot. */
1957     JSFunction *fun = (JSFunction *) obj->getPrivate();
1958     if (!fun)
1959         return;
1960
1961     if (fun != obj) {
1962         /* obj is a cloned function object, trace the clone-parent, fun. */
1963         MarkObject(trc, *fun, "private");
1964
1965         /* The function could be a flat closure with upvar copies in the clone. */
1966         if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars()) {
1967             MarkValueRange(trc, fun->script()->bindings.countUpvars(),
1968                            obj->getFlatClosureUpvars(), "upvars");
1969         }
1970         return;
1971     }
1972
1973     if (fun->atom)
1974         MarkString(trc, ATOM_TO_STRING(fun->atom), "atom");
1975
1976     if (fun->isInterpreted() && fun->script())
1977         js_TraceScript(trc, fun->script());
1978 }
1979
1980 static void
1981 fun_finalize(JSContext *cx, JSObject *obj)
1982 {
1983     /* Ignore newborn function objects. */
1984     JSFunction *fun = obj->getFunctionPrivate();
1985     if (!fun)
1986         return;
1987
1988     /* Cloned function objects may be flat closures with upvars to free. */
1989     if (fun != obj) {
1990         if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars())
1991             cx->free((void *) obj->getFlatClosureUpvars());
1992         return;
1993     }
1994
1995     /*
1996      * Null-check fun->script() because the parser sets interpreted very early.
1997      */
1998     if (fun->isInterpreted() && fun->script())
1999         js_DestroyScriptFromGC(cx, fun->script());
2000 }
2001
2002 /*
2003  * Reserve two slots in all function objects for XPConnect.  Note that this
2004  * does not bloat every instance, only those on which reserved slots are set,
2005  * and those on which ad-hoc properties are defined.
2006  */
2007 JS_PUBLIC_DATA(Class) js_FunctionClass = {
2008     js_Function_str,
2009     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
2010     JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
2011     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
2012     PropertyStub,         /* addProperty */
2013     PropertyStub,         /* delProperty */
2014     PropertyStub,         /* getProperty */
2015     StrictPropertyStub,   /* setProperty */
2016     fun_enumerate,
2017     (JSResolveOp)fun_resolve,
2018     ConvertStub,
2019     fun_finalize,
2020     NULL,                 /* reserved0   */
2021     NULL,                 /* checkAccess */
2022     NULL,                 /* call        */
2023     NULL,                 /* construct   */
2024     js_XDRFunctionObject,
2025     fun_hasInstance,
2026     JS_CLASS_TRACE(fun_trace)
2027 };
2028
2029 JSString *
2030 fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent)
2031 {
2032     if (!obj->isFunction()) {
2033         if (obj->isFunctionProxy())
2034             return JSProxy::fun_toString(cx, obj, indent);
2035         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2036                              JSMSG_INCOMPATIBLE_PROTO,
2037                              js_Function_str, js_toString_str,
2038                              "object");
2039         return NULL;
2040     }
2041
2042     JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
2043     if (!fun)
2044         return NULL;
2045
2046     if (!indent) {
2047         ToSourceCache::Ptr p = cx->compartment->toSourceCache.lookup(fun);
2048         if (p)
2049             return p->value;
2050     }
2051
2052     JSString *str = JS_DecompileFunction(cx, fun, indent);
2053     if (!str)
2054         return false;
2055
2056     if (!indent)
2057         cx->compartment->toSourceCache.put(fun, str);
2058
2059     return str;
2060 }
2061
2062 static JSBool
2063 fun_toString(JSContext *cx, uintN argc, Value *vp)
2064 {
2065     JS_ASSERT(IsFunctionObject(vp[0]));
2066     uint32_t indent = 0;
2067
2068     if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent))
2069         return false;
2070
2071     JSObject *obj = ToObject(cx, &vp[1]);
2072     if (!obj)
2073         return false;
2074
2075     JSString *str = fun_toStringHelper(cx, obj, indent);
2076     if (!str)
2077         return false;
2078
2079     vp->setString(str);
2080     return true;
2081 }
2082
2083 #if JS_HAS_TOSOURCE
2084 static JSBool
2085 fun_toSource(JSContext *cx, uintN argc, Value *vp)
2086 {
2087     JS_ASSERT(IsFunctionObject(vp[0]));
2088
2089     JSObject *obj = ToObject(cx, &vp[1]);
2090     if (!obj)
2091         return false;
2092
2093     JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
2094     if (!str)
2095         return false;
2096
2097     vp->setString(str);
2098     return true;
2099 }
2100 #endif
2101
2102 JSBool
2103 js_fun_call(JSContext *cx, uintN argc, Value *vp)
2104 {
2105     LeaveTrace(cx);
2106     Value fval = vp[1];
2107
2108     if (!js_IsCallable(fval)) {
2109         if (JSString *str = js_ValueToString(cx, fval)) {
2110             JSAutoByteString bytes(cx, str);
2111             if (!!bytes) {
2112                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2113                                      JSMSG_INCOMPATIBLE_PROTO,
2114                                      js_Function_str, js_call_str,
2115                                      bytes.ptr());
2116             }
2117         }
2118         return false;
2119     }
2120
2121     Value *argv = vp + 2;
2122     Value thisv;
2123     if (argc == 0) {
2124         thisv.setUndefined();
2125     } else {
2126         thisv = argv[0];
2127
2128         argc--;
2129         argv++;
2130     }
2131
2132     /* Allocate stack space for fval, obj, and the args. */
2133     InvokeArgsGuard args;
2134     if (!cx->stack().pushInvokeArgs(cx, argc, &args))
2135         return JS_FALSE;
2136
2137     /* Push fval, thisv, and the args. */
2138     args.callee() = fval;
2139     args.thisv() = thisv;
2140     memcpy(args.argv(), argv, argc * sizeof *argv);
2141
2142     bool ok = Invoke(cx, args, 0);
2143     *vp = args.rval();
2144     return ok;
2145 }
2146
2147 /* ES5 15.3.4.3 */
2148 JSBool
2149 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
2150 {
2151     /* Step 1. */
2152     Value fval = vp[1];
2153     if (!js_IsCallable(fval)) {
2154         if (JSString *str = js_ValueToString(cx, fval)) {
2155             JSAutoByteString bytes(cx, str);
2156             if (!!bytes) {
2157                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2158                                      JSMSG_INCOMPATIBLE_PROTO,
2159                                      js_Function_str, js_apply_str,
2160                                      bytes.ptr());
2161             }
2162         }
2163         return false;
2164     }
2165
2166     /* Step 2. */
2167     if (argc < 2 || vp[3].isNullOrUndefined())
2168         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
2169
2170     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
2171
2172     /* Step 3. */
2173     if (!vp[3].isObject()) {
2174         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
2175         return false;
2176     }
2177
2178     /*
2179      * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
2180      * original version of ES5).
2181      */
2182     JSObject *aobj = &vp[3].toObject();
2183     jsuint length;
2184     if (!js_GetLengthProperty(cx, aobj, &length))
2185         return false;
2186
2187     LeaveTrace(cx);
2188
2189     /* Step 6. */
2190     uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
2191
2192     InvokeArgsGuard args;
2193     if (!cx->stack().pushInvokeArgs(cx, n, &args))
2194         return false;
2195
2196     /* Push fval, obj, and aobj's elements as args. */
2197     args.callee() = fval;
2198     args.thisv() = vp[2];
2199
2200     /* Steps 7-8. */
2201     if (!GetElements(cx, aobj, n, args.argv()))
2202         return false;
2203
2204     /* Step 9. */
2205     if (!Invoke(cx, args, 0))
2206         return false;
2207     *vp = args.rval();
2208     return true;
2209 }
2210
2211 namespace js {
2212
2213 JSBool
2214 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp);
2215
2216 }
2217
2218 inline bool
2219 JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
2220                             const Value *args, uintN argslen)
2221 {
2222     JS_ASSERT(isFunction());
2223
2224     flags |= JSObject::BOUND_FUNCTION;
2225     getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
2226     getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen);
2227     if (argslen != 0) {
2228         /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
2229         EmptyShape *empty = EmptyShape::create(cx, clasp);
2230         if (!empty)
2231             return false;
2232
2233         empty->slotSpan += argslen;
2234         map = empty;
2235
2236         if (!ensureInstanceReservedSlots(cx, argslen))
2237             return false;
2238
2239         JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
2240         memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
2241     }
2242     return true;
2243 }
2244
2245 inline JSObject *
2246 JSObject::getBoundFunctionTarget() const
2247 {
2248     JS_ASSERT(isFunction());
2249     JS_ASSERT(isBoundFunction());
2250
2251     /* Bound functions abuse |parent| to store their target function. */
2252     return getParent();
2253 }
2254
2255 inline const js::Value &
2256 JSObject::getBoundFunctionThis() const
2257 {
2258     JS_ASSERT(isFunction());
2259     JS_ASSERT(isBoundFunction());
2260
2261     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
2262 }
2263
2264 inline const js::Value *
2265 JSObject::getBoundFunctionArguments(uintN &argslen) const
2266 {
2267     JS_ASSERT(isFunction());
2268     JS_ASSERT(isBoundFunction());
2269
2270     argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
2271     JS_ASSERT_IF(argslen > 0, numSlots() >= argslen);
2272
2273     return getSlots() + FUN_CLASS_RESERVED_SLOTS;
2274 }
2275
2276 namespace js {
2277
2278 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
2279 JSBool
2280 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
2281 {
2282     JSObject *obj = &vp[0].toObject();
2283     JS_ASSERT(obj->isFunction());
2284     JS_ASSERT(obj->isBoundFunction());
2285
2286     LeaveTrace(cx);
2287
2288     bool constructing = IsConstructing(vp);
2289
2290     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
2291     uintN argslen;
2292     const Value *boundArgs = obj->getBoundFunctionArguments(argslen);
2293
2294     if (argc + argslen > JS_ARGS_LENGTH_MAX) {
2295         js_ReportAllocationOverflow(cx);
2296         return false;
2297     }
2298
2299     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
2300     JSObject *target = obj->getBoundFunctionTarget();
2301
2302     /* 15.3.4.5.1 step 2. */
2303     const Value &boundThis = obj->getBoundFunctionThis();
2304
2305     InvokeArgsGuard args;
2306     if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
2307         return false;
2308
2309     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
2310     memcpy(args.argv(), boundArgs, argslen * sizeof(Value));
2311     memcpy(args.argv() + argslen, vp + 2, argc * sizeof(Value));
2312
2313     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
2314     args.callee().setObject(*target);
2315
2316     if (!constructing)
2317         args.thisv() = boundThis;
2318
2319     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args, 0))
2320         return false;
2321
2322     *vp = args.rval();
2323     return true;
2324 }
2325
2326 }
2327
2328 /* ES5 15.3.4.5. */
2329 static JSBool
2330 fun_bind(JSContext *cx, uintN argc, Value *vp)
2331 {
2332     /* Step 1. */
2333     Value &thisv = vp[1];
2334
2335     /* Step 2. */
2336     if (!js_IsCallable(thisv)) {
2337         if (JSString *str = js_ValueToString(cx, thisv)) {
2338             JSAutoByteString bytes(cx, str);
2339             if (!!bytes) {
2340                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2341                                      JSMSG_INCOMPATIBLE_PROTO,
2342                                      js_Function_str, "bind", bytes.ptr());
2343             }
2344         }
2345         return false;
2346     }
2347
2348     JSObject *target = &thisv.toObject();
2349
2350     /* Step 3. */
2351     Value *args = NULL;
2352     uintN argslen = 0;
2353     if (argc > 1) {
2354         args = vp + 3;
2355         argslen = argc - 1;
2356     }
2357
2358     /* Steps 15-16. */
2359     uintN length = 0;
2360     if (target->isFunction()) {
2361         uintN nargs = target->getFunctionPrivate()->nargs;
2362         if (nargs > argslen)
2363             length = nargs - argslen;
2364     }
2365
2366     /* Step 4-6, 10-11. */
2367     JSAtom *name = target->isFunction() ? target->getFunctionPrivate()->atom : NULL;
2368
2369     /* NB: Bound functions abuse |parent| to store their target. */
2370     JSObject *funobj =
2371         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
2372                        JSFUN_CONSTRUCTOR, target, name);
2373     if (!funobj)
2374         return false;
2375
2376     /* Steps 7-9. */
2377     Value thisArg = argc >= 1 ? vp[2] : UndefinedValue();
2378     if (!funobj->initBoundFunction(cx, thisArg, args, argslen))
2379         return false;
2380
2381     /* Steps 17, 19-21 are handled by fun_resolve. */
2382     /* Step 18 is the default for new functions. */
2383
2384     /* Step 22. */
2385     vp->setObject(*funobj);
2386     return true;
2387 }
2388
2389 static JSFunctionSpec function_methods[] = {
2390 #if JS_HAS_TOSOURCE
2391     JS_FN(js_toSource_str,   fun_toSource,   0,0),
2392 #endif
2393     JS_FN(js_toString_str,   fun_toString,   0,0),
2394     JS_FN(js_apply_str,      js_fun_apply,   2,0),
2395     JS_FN(js_call_str,       js_fun_call,    1,0),
2396     JS_FN("bind",            fun_bind,       1,0),
2397     JS_FS_END
2398 };
2399
2400 static JSBool
2401 Function(JSContext *cx, uintN argc, Value *vp)
2402 {
2403     JSObject *obj = NewFunction(cx, NULL);
2404     if (!obj)
2405         return JS_FALSE;
2406
2407     /* N.B. overwriting callee with return value */
2408     JSObject *parent = vp[0].toObject().getParent();
2409     vp[0].setObject(*obj);
2410
2411     /*
2412      * NB: (new Function) is not lexically closed by its caller, it's just an
2413      * anonymous function in the top-level scope that its constructor inhabits.
2414      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2415      * and so would a call to f from another top-level's script or function.
2416      *
2417      * In older versions, before call objects, a new Function was adopted by
2418      * its running context's globalObject, which might be different from the
2419      * top-level reachable from scopeChain (in HTML frames, e.g.).
2420      */
2421     JSFunction *fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
2422                                      parent, cx->runtime->atomState.anonymousAtom);
2423     if (!fun)
2424         return JS_FALSE;
2425
2426     /*
2427      * Function is static and not called directly by other functions in this
2428      * file, therefore it is callable only as a native function by js_Invoke.
2429      * Find the scripted caller, possibly skipping other native frames such as
2430      * are built for Function.prototype.call or .apply activations that invoke
2431      * Function indirectly from a script.
2432      */
2433     JSStackFrame *caller = js_GetScriptedCaller(cx, NULL);
2434     uintN lineno;
2435     const char *filename;
2436     JSPrincipals *principals;
2437     if (caller) {
2438         JSObject *callee = &JS_CALLEE(cx, vp).toObject();
2439         principals = js_EvalFramePrincipals(cx, callee, caller);
2440         filename = js_ComputeFilename(cx, caller, principals, &lineno);
2441     } else {
2442         filename = NULL;
2443         lineno = 0;
2444         principals = NULL;
2445     }
2446
2447     /* Belt-and-braces: check that the caller has access to parent. */
2448     if (!js_CheckPrincipalsAccess(cx, parent, principals,
2449                                   CLASS_ATOM(cx, Function))) {
2450         return JS_FALSE;
2451     }
2452
2453     /*
2454      * CSP check: whether new Function() is allowed at all.
2455      * Report errors via CSP is done in the script security manager.
2456      * js_CheckContentSecurityPolicy is defined in jsobj.cpp
2457      */
2458     if (!js_CheckContentSecurityPolicy(cx, parent)) {
2459         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
2460         return JS_FALSE;
2461     }
2462
2463     Bindings bindings(cx);
2464     AutoBindingsRooter root(cx, bindings);
2465
2466     Value *argv = vp + 2;
2467     uintN n = argc ? argc - 1 : 0;
2468     if (n > 0) {
2469         enum { OK, BAD, BAD_FORMAL } state;
2470
2471         /*
2472          * Collect the function-argument arguments into one string, separated
2473          * by commas, then make a tokenstream from that string, and scan it to
2474          * get the arguments.  We need to throw the full scanner at the
2475          * problem, because the argument string can legitimately contain
2476          * comments and linefeeds.  XXX It might be better to concatenate
2477          * everything up into a function definition and pass it to the
2478          * compiler, but doing it this way is less of a delta from the old
2479          * code.  See ECMA 15.3.2.1.
2480          */
2481         state = BAD_FORMAL;
2482         size_t args_length = 0;
2483         for (uintN i = 0; i < n; i++) {
2484             /* Collect the lengths for all the function-argument arguments. */
2485             JSString *arg = js_ValueToString(cx, argv[i]);
2486             if (!arg)
2487                 return JS_FALSE;
2488             argv[i].setString(arg);
2489
2490             /*
2491              * Check for overflow.  The < test works because the maximum
2492              * JSString length fits in 2 fewer bits than size_t has.
2493              */
2494             size_t old_args_length = args_length;
2495             args_length = old_args_length + arg->length();
2496             if (args_length < old_args_length) {
2497                 js_ReportAllocationOverflow(cx);
2498                 return JS_FALSE;
2499             }
2500         }
2501
2502         /* Add 1 for each joining comma and check for overflow (two ways). */
2503         size_t old_args_length = args_length;
2504         args_length = old_args_length + n - 1;
2505         if (args_length < old_args_length ||
2506             args_length >= ~(size_t)0 / sizeof(jschar)) {
2507             js_ReportAllocationOverflow(cx);
2508             return JS_FALSE;
2509         }
2510
2511         /*
2512          * Allocate a string to hold the concatenated arguments, including room
2513          * for a terminating 0.  Mark cx->tempPool for later release, to free
2514          * collected_args and its tokenstream in one swoop.
2515          */
2516         void *mark = JS_ARENA_MARK(&cx->tempPool);
2517         jschar *cp;
2518         JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
2519                                (args_length+1) * sizeof(jschar));
2520         if (!cp) {
2521             js_ReportOutOfScriptQuota(cx);
2522             return JS_FALSE;
2523         }
2524         jschar *collected_args = cp;
2525
2526         /*
2527          * Concatenate the arguments into the new string, separated by commas.
2528          */
2529         for (uintN i = 0; i < n; i++) {
2530             JSString *arg = argv[i].toString();
2531             size_t arg_length = arg->length();
2532             const jschar *arg_chars = arg->getChars(cx);
2533             if (!arg_chars) {
2534                 JS_ARENA_RELEASE(&cx->tempPool, mark);
2535                 return JS_FALSE;
2536             }
2537             (void) js_strncpy(cp, arg_chars, arg_length);
2538             cp += arg_length;
2539
2540             /* Add separating comma or terminating 0. */
2541             *cp++ = (i + 1 < n) ? ',' : 0;
2542         }
2543
2544         /* Initialize a tokenstream that reads from the given string. */
2545         TokenStream ts(cx);
2546         if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion())) {
2547             JS_ARENA_RELEASE(&cx->tempPool, mark);
2548             return JS_FALSE;
2549         }
2550
2551         /* The argument string may be empty or contain no tokens. */
2552         TokenKind tt = ts.getToken();
2553         if (tt != TOK_EOF) {
2554             for (;;) {
2555                 /*
2556                  * Check that it's a name.  This also implicitly guards against
2557                  * TOK_ERROR, which was already reported.
2558                  */
2559                 if (tt != TOK_NAME)
2560                     goto after_args;
2561
2562                 /*
2563                  * Get the atom corresponding to the name from the token
2564                  * stream; we're assured at this point that it's a valid
2565                  * identifier.
2566                  */
2567                 JSAtom *atom = ts.currentToken().t_atom;
2568
2569                 /* Check for a duplicate parameter name. */
2570                 if (bindings.hasBinding(cx, atom)) {
2571                     JSAutoByteString name;
2572                     if (!js_AtomToPrintableString(cx, atom, &name)) {
2573                         state = BAD;
2574                         goto after_args;
2575                     }
2576                     if (!ReportCompileErrorNumber(cx, &ts, NULL,
2577                                                   JSREPORT_WARNING | JSREPORT_STRICT,
2578                                                   JSMSG_DUPLICATE_FORMAL, name.ptr())) {
2579                         state = BAD;
2580                         goto after_args;
2581                     }
2582                 }
2583
2584                 uint16 dummy;
2585                 if (!bindings.addArgument(cx, atom, &dummy)) {
2586                     state = BAD;
2587                     goto after_args;
2588                 }
2589
2590                 /*
2591                  * Get the next token.  Stop on end of stream.  Otherwise
2592                  * insist on a comma, get another name, and iterate.
2593                  */
2594                 tt = ts.getToken();
2595                 if (tt == TOK_EOF)
2596                     break;
2597                 if (tt != TOK_COMMA)
2598                     goto after_args;
2599                 tt = ts.getToken();
2600             }
2601         }
2602
2603         state = OK;
2604       after_args:
2605         if (state == BAD_FORMAL && !ts.isError()) {
2606             /*
2607              * Report "malformed formal parameter" iff no illegal char or
2608              * similar scanner error was already reported.
2609              */
2610             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2611                                  JSMSG_BAD_FORMAL);
2612         }
2613         ts.close();
2614         JS_ARENA_RELEASE(&cx->tempPool, mark);
2615         if (state != OK)
2616             return JS_FALSE;
2617     }
2618
2619     JSString *str;
2620     if (argc) {
2621         str = js_ValueToString(cx, argv[argc - 1]);
2622         if (!str)
2623             return JS_FALSE;
2624         argv[argc - 1].setString(str);
2625     } else {
2626         str = cx->runtime->emptyString;
2627     }
2628
2629     size_t length = str->length();
2630     const jschar *chars = str->getChars(cx);
2631     if (!chars)
2632         return JS_FALSE;
2633
2634     return Compiler::compileFunctionBody(cx, fun, principals, &bindings,
2635                                          chars, length, filename, lineno, cx->findVersion());
2636 }
2637
2638 namespace js {
2639
2640 JS_FRIEND_API(bool)
2641 IsBuiltinFunctionConstructor(JSFunction *fun)
2642 {
2643     return fun->maybeNative() == Function;
2644 }
2645
2646 const Shape *
2647 LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
2648 {
2649 #ifdef DEBUG
2650     JSFunction *fun = funobj->getFunctionPrivate();
2651     JS_ASSERT(fun->isInterpreted());
2652     JS_ASSERT(!fun->isFunctionPrototype());
2653     JS_ASSERT(!funobj->isBoundFunction());
2654 #endif
2655
2656     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
2657     const Shape *shape = funobj->nativeLookup(id);
2658     if (!shape) {
2659         if (!ResolveInterpretedFunctionPrototype(cx, funobj))
2660             return false;
2661         shape = funobj->nativeLookup(id);
2662     }
2663     JS_ASSERT(!shape->configurable());
2664     JS_ASSERT(shape->isDataDescriptor());
2665     JS_ASSERT(shape->hasSlot());
2666     JS_ASSERT(!shape->isMethod());
2667     return shape;
2668 }
2669
2670 } /* namespace js */
2671
2672 static JSBool
2673 ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
2674 {
2675     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
2676                                  JSMSG_THROW_TYPE_ERROR);
2677     return false;
2678 }
2679
2680 JSObject *
2681 js_InitFunctionClass(JSContext *cx, JSObject *obj)
2682 {
2683     JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
2684                                    NULL, function_methods, NULL, NULL);
2685     if (!proto)
2686         return NULL;
2687
2688     JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
2689     if (!fun)
2690         return NULL;
2691     fun->flags |= JSFUN_PROTOTYPE;
2692
2693     JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT);
2694     if (!script)
2695         return NULL;
2696     script->noScriptRval = true;
2697     script->code[0] = JSOP_STOP;
2698     script->code[1] = SRC_NULL;
2699 #ifdef CHECK_SCRIPT_OWNER
2700     script->owner = NULL;
2701 #endif
2702     fun->u.i.script = script;
2703
2704     if (obj->isGlobal()) {
2705         /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
2706         JSObject *throwTypeError =
2707             js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
2708                            0, obj, NULL);
2709         if (!throwTypeError)
2710             return NULL;
2711
2712         JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR,
2713                                           ObjectValue(*throwTypeError)));
2714     }
2715
2716     return proto;
2717 }
2718
2719 JSFunction *
2720 js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
2721                uintN flags, JSObject *parent, JSAtom *atom)
2722 {
2723     JSFunction *fun;
2724
2725     if (funobj) {
2726         JS_ASSERT(funobj->isFunction());
2727         funobj->setParent(parent);
2728     } else {
2729         funobj = NewFunction(cx, parent);
2730         if (!funobj)
2731             return NULL;
2732     }
2733     JS_ASSERT(!funobj->getPrivate());
2734     fun = (JSFunction *) funobj;
2735
2736     /* Initialize all function members. */
2737     fun->nargs = uint16(nargs);
2738     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
2739     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
2740         JS_ASSERT(!native);
2741         JS_ASSERT(nargs == 0);
2742         fun->u.i.skipmin = 0;
2743         fun->u.i.wrapper = false;
2744         fun->u.i.script = NULL;
2745     } else {
2746         fun->u.n.clasp = NULL;
2747         if (flags & JSFUN_TRCINFO) {
2748 #ifdef JS_TRACER
2749             JSNativeTraceInfo *trcinfo =
2750                 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native);
2751             fun->u.n.native = (js::Native) trcinfo->native;
2752             fun->u.n.trcinfo = trcinfo;
2753 #else
2754             fun->u.n.trcinfo = NULL;
2755 #endif
2756         } else {
2757             fun->u.n.native = native;
2758             fun->u.n.trcinfo = NULL;
2759         }
2760         JS_ASSERT(fun->u.n.native);
2761     }
2762     fun->atom = atom;
2763
2764     /* Set private to self to indicate non-cloned fully initialized function. */
2765     FUN_OBJECT(fun)->setPrivate(fun);
2766     return fun;
2767 }
2768
2769 JSObject * JS_FASTCALL
2770 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
2771                        JSObject *proto)
2772 {
2773     JS_ASSERT(parent);
2774     JS_ASSERT(proto);
2775
2776     JSObject *clone;
2777     if (cx->compartment == fun->compartment()) {
2778         /*
2779          * The cloned function object does not need the extra JSFunction members
2780          * beyond JSObject as it points to fun via the private slot.
2781          */
2782         clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
2783         if (!clone)
2784             return NULL;
2785         clone->setPrivate(fun);
2786     } else {
2787         /*
2788          * Across compartments we have to deep copy JSFunction and clone the
2789          * script (for interpreted functions).
2790          */
2791         clone = NewFunction(cx, parent);
2792         if (!clone)
2793             return NULL;
2794         JSFunction *cfun = (JSFunction *) clone;
2795         cfun->nargs = fun->nargs;
2796         cfun->flags = fun->flags;
2797         cfun->u = fun->getFunctionPrivate()->u;
2798         cfun->atom = fun->atom;
2799         clone->setPrivate(cfun);
2800         if (cfun->isInterpreted()) {
2801             JSScript *script = cfun->u.i.script;
2802             JS_ASSERT(script);
2803             JS_ASSERT(script->compartment == fun->compartment());
2804             JS_ASSERT(script->compartment != cx->compartment);
2805
2806             cfun->u.i.script = js_CloneScript(cx, script);
2807             if (!cfun->u.i.script)
2808                 return NULL;
2809 #ifdef CHECK_SCRIPT_OWNER
2810             cfun->script()->owner = NULL;
2811 #endif
2812             js_CallNewScriptHook(cx, cfun->script(), cfun);
2813         }
2814     }
2815     return clone;
2816 }
2817
2818 #ifdef JS_TRACER
2819 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0,
2820                      nanojit::ACCSET_STORE_ANY)
2821 #endif
2822
2823 /*
2824  * Create a new flat closure, but don't initialize the imported upvar
2825  * values. The tracer calls this function and then initializes the upvar
2826  * slots on trace.
2827  */
2828 JSObject * JS_FASTCALL
2829 js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
2830 {
2831     JS_ASSERT(fun->isFlatClosure());
2832     JS_ASSERT(JSScript::isValidOffset(fun->script()->upvarsOffset) ==
2833               fun->script()->bindings.hasUpvars());
2834     JS_ASSERT_IF(JSScript::isValidOffset(fun->script()->upvarsOffset),
2835                  fun->script()->upvars()->length == fun->script()->bindings.countUpvars());
2836
2837     JSObject *closure = CloneFunctionObject(cx, fun, scopeChain);
2838     if (!closure)
2839         return closure;
2840
2841     uint32 nslots = fun->script()->bindings.countUpvars();
2842     if (nslots == 0)
2843         return closure;
2844
2845     Value *upvars = (Value *) cx->malloc(nslots * sizeof(Value));
2846     if (!upvars)
2847         return NULL;
2848
2849     closure->setFlatClosureUpvars(upvars);
2850     return closure;
2851 }
2852
2853 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
2854                      CONTEXT, FUNCTION, OBJECT, 0, nanojit::ACCSET_STORE_ANY)
2855
2856 JSObject *
2857 js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
2858 {
2859     /*
2860      * Flat closures cannot yet be partial, that is, all upvars must be copied,
2861      * or the closure won't be flattened. Therefore they do not need to search
2862      * enclosing scope objects via JSOP_NAME, etc.
2863      *
2864      * FIXME: bug 545759 proposes to enable partial flat closures. Fixing this
2865      * bug requires a GetScopeChainFast call here, along with JS_REQUIRES_STACK
2866      * annotations on this function's prototype and definition.
2867      */
2868     VOUCH_DOES_NOT_REQUIRE_STACK();
2869     JSObject *scopeChain = &cx->fp()->scopeChain();
2870
2871     JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain);
2872     if (!closure || !fun->script()->bindings.hasUpvars())
2873         return closure;
2874
2875     Value *upvars = closure->getFlatClosureUpvars();
2876     uintN level = fun->u.i.script->staticLevel;
2877     JSUpvarArray *uva = fun->script()->upvars();
2878
2879     for (uint32 i = 0, n = uva->length; i < n; i++)
2880         upvars[i] = GetUpvar(cx, level, uva->vector[i]);
2881
2882     return closure;
2883 }
2884
2885 JSObject *
2886 js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
2887 {
2888     JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
2889     JS_ASSERT(!cx->fp()->fun()->optimizedClosure());
2890     JS_ASSERT(FUN_FLAT_CLOSURE(fun));
2891
2892     return WrapEscapingClosure(cx, cx->fp(), fun);
2893 }
2894
2895 JSFunction *
2896 js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
2897                   uintN nargs, uintN attrs)
2898 {
2899     PropertyOp gop;
2900     StrictPropertyOp sop;
2901     JSFunction *fun;
2902
2903     if (attrs & JSFUN_STUB_GSOPS) {
2904         /*
2905          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2906          * the defined property's attributes. This allows us to encode another,
2907          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2908          * for more on this.
2909          */
2910         attrs &= ~JSFUN_STUB_GSOPS;
2911         gop = PropertyStub;
2912         sop = StrictPropertyStub;
2913     } else {
2914         gop = NULL;
2915         sop = NULL;
2916     }
2917
2918     /*
2919      * Historically, all objects have had a parent member as intrinsic scope
2920      * chain link. We want to move away from this universal parent, but JS
2921      * requires that function objects have something like parent (ES3 and ES5
2922      * call it the [[Scope]] internal property), to bake a particular static
2923      * scope environment into each function object.
2924      *
2925      * All function objects thus have parent, including all native functions.
2926      * All native functions defined by the JS_DefineFunction* APIs are created
2927      * via the call below to js_NewFunction, which passes obj as the parent
2928      * parameter, and so binds fun's parent to obj using JSObject::setParent,
2929      * under js_NewFunction (in JSObject::init, called from NewObject -- see
2930      * jsobjinlines.h).
2931      *
2932      * But JSObject::setParent sets the DELEGATE object flag on its receiver,
2933      * to mark the object as a proto or parent of another object. Such objects
2934      * may intervene in property lookups and scope chain searches, so require
2935      * special handling when caching lookup and search results (since such
2936      * intervening objects can in general grow shadowing properties later).
2937      *
2938      * Thus using setParent prematurely flags certain objects, notably class
2939      * prototypes, so that defining native methods on them, where the method's
2940      * name (e.g., toString) is already bound on Object.prototype, triggers
2941      * shadowingShapeChange events and gratuitous shape regeneration.
2942      *
2943      * To fix this longstanding bug, we set check whether obj is already a
2944      * delegate, and if not, then if js_NewFunction flagged obj as a delegate,
2945      * we clear the flag.
2946      *
2947      * We thus rely on the fact that native functions (including indirect eval)
2948      * do not use the property cache or equivalent JIT techniques that require
2949      * this bit to be set on their parent-linked scope chain objects.
2950      *
2951      * Note: we keep API compatibility by setting parent to obj for all native
2952      * function objects, even if obj->getGlobal() would suffice. This should be
2953      * revisited when parent is narrowed to exist only for function objects and
2954      * possibly a few prehistoric scope objects (e.g. event targets).
2955      *
2956      * FIXME: bug 611190.
2957      */
2958     bool wasDelegate = obj->isDelegate();
2959
2960     fun = js_NewFunction(cx, NULL, native, nargs,
2961                          attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
2962                          obj,
2963                          JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
2964     if (!fun)
2965         return NULL;
2966
2967     if (!wasDelegate && obj->isDelegate())
2968         obj->clearDelegate();
2969
2970     if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
2971         return NULL;
2972     return fun;
2973 }
2974
2975 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2976 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2977 #endif
2978
2979 JSFunction *
2980 js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags)
2981 {
2982     JSObject *funobj;
2983     if (!IsFunctionObject(*vp, &funobj)) {
2984         js_ReportIsNotFunction(cx, vp, flags);
2985         return NULL;
2986     }
2987     return GET_FUNCTION_PRIVATE(cx, funobj);
2988 }
2989
2990 JSObject *
2991 js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags)
2992 {
2993     JSObject *funobj;
2994     if (!IsFunctionObject(*vp, &funobj)) {
2995         js_ReportIsNotFunction(cx, vp, flags);
2996         return NULL;
2997     }
2998
2999     return funobj;
3000 }
3001
3002 JSObject *
3003 js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags)
3004 {
3005     if (vp->isObject()) {
3006         JSObject *callable = &vp->toObject();
3007         if (callable->isCallable())
3008             return callable;
3009     }
3010
3011     js_ReportIsNotFunction(cx, vp, flags);
3012     return NULL;
3013 }
3014
3015 void
3016 js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
3017 {
3018     const char *name = NULL, *source = NULL;
3019     AutoValueRooter tvr(cx);
3020     uintN error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
3021     LeaveTrace(cx);
3022
3023     /*
3024      * We try to the print the code that produced vp if vp is a value in the
3025      * most recent interpreted stack frame. Note that additional values, not
3026      * directly produced by the script, may have been pushed onto the frame's
3027      * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
3028      * the depth simulated by ReconstructPCStack.
3029      *
3030      * Conversely, values may have been popped from the stack in preparation
3031      * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from
3032      * the top of the simulated stack to js_ReportValueError3, we do bounds
3033      * checking using the minimum of both the simulated and actual stack depth.
3034      */
3035     ptrdiff_t spindex = 0;
3036
3037     FrameRegsIter i(cx);
3038     while (!i.done() && !i.pc())
3039         ++i;
3040
3041     if (!i.done()) {
3042         uintN depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc());
3043         Value *simsp = i.fp()->base() + depth;
3044         if (i.fp()->base() <= vp && vp < Min(simsp, i.sp()))
3045             spindex = vp - simsp;
3046     }
3047
3048     if (!spindex)
3049         spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
3050
3051     js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
3052 }