1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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.
39 * ***** END LICENSE BLOCK ***** */
42 * JS function support.
53 #include "jsbuiltins.h"
55 #include "jsversion.h"
65 #include "jspropertytree.h"
72 #include "jsstaticcheck.h"
80 # include "jsxdrapi.h"
84 #include "methodjit/MethodJIT.h"
87 #include "jsatominlines.h"
88 #include "jscntxtinlines.h"
89 #include "jsfuninlines.h"
90 #include "jsinterpinlines.h"
91 #include "jsobjinlines.h"
92 #include "jsscriptinlines.h"
95 using namespace js::gc;
98 JSObject::getThrowTypeError() const
100 return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR).toObject();
104 js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
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);
113 argsobj = js_GetArgsObject(cx, fp);
116 vp->setObject(*argsobj);
121 js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
123 JS_ASSERT(fp->isFunctionFrame());
125 if (fp->hasOverriddenArgs()) {
126 JS_ASSERT(fp->hasCallObj());
128 jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
130 if (!fp->callObj().getProperty(cx, argumentsid, &v))
134 if (v.isPrimitive()) {
135 obj = js_ValueToNonNullObject(cx, v);
141 return obj->getProperty(cx, id, vp);
145 if (JSID_IS_INT(id)) {
146 uint32 arg = uint32(JSID_TO_INT(id));
147 JSObject *argsobj = fp->maybeArgsObj();
148 if (arg < fp->numActualArgs()) {
150 if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
151 return argsobj->getProperty(cx, id, vp);
153 *vp = fp->canonicalActualArg(arg);
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
160 * function f(x) { x = 42; return arguments[0]; }
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
168 return argsobj->getProperty(cx, id, vp);
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());
180 NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
183 if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
186 JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2);
187 JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
191 ArgumentsData *data = (ArgumentsData *)
192 cx->malloc(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
195 SetValueRangeToUndefined(data->slots, argc);
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);
203 argsobj->setMap(cx->compartment->emptyArgumentsShape);
205 argsobj->setArgsLength(argc);
206 argsobj->setArgsData(data);
207 data->callee.setObject(callee);
212 struct STATIC_SKIP_INFERENCE PutArg
214 PutArg(Value *dst) : dst(dst) {}
216 void operator()(uintN, Value *src) {
217 if (!dst->isMagic(JS_ARGS_HOLE))
224 js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
227 * We must be in a function activation; the function must be lightweight
228 * or else fp must have a variable object.
230 JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
232 while (fp->isEvalOrDebuggerFrame())
235 /* Create an arguments object for fp only if it lacks one. */
236 if (fp->hasArgsObj())
237 return &fp->argsObj();
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());
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.
254 if (argsobj->isStrictArguments())
255 fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
257 argsobj->setPrivate(fp);
259 fp->setArgsObj(*argsobj);
264 js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
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);
272 JS_ASSERT(!argsobj.getPrivate());
280 * Traced versions of js_GetArgsObject and js_PutArgsObject.
282 JSObject * JS_FASTCALL
283 js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
285 JSObject *argsobj = NewArguments(cx, parent, argc, *callee);
289 if (argsobj->isStrictArguments()) {
291 * Strict mode callers must copy arguments into the created arguments
292 * object. The trace-JITting code is in TraceRecorder::newArguments.
294 JS_ASSERT(!argsobj->getPrivate());
296 argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
301 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UINT32, OBJECT,
302 0, nanojit::ACCSET_STORE_ANY)
304 /* FIXME change the return type to void. */
306 js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
308 JS_ASSERT(argsobj->isNormalArguments());
309 JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
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.
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))
323 argsobj->setPrivate(NULL);
326 JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
327 nanojit::ACCSET_STORE_ANY)
329 #endif /* JS_TRACER */
332 args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
334 JS_ASSERT(obj->isArguments());
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));
348 static JS_REQUIRES_STACK JSObject *
349 WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
351 JS_ASSERT(fun->optimizedClosure());
352 JS_ASSERT(!fun->u.i.wrapper);
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!
361 JSObject *scopeChain = GetScopeChain(cx, fp);
365 JSObject *wfunobj = NewFunction(cx, scopeChain);
368 AutoObjectRooter tvr(cx, wfunobj);
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;
379 JSScript *script = fun->script();
380 jssrcnote *snbase = script->notes();
381 jssrcnote *sn = snbase;
382 while (!SN_IS_TERMINATOR(sn))
384 uintN nsrcnotes = (sn - snbase) + 1;
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
392 script->bindings.countUpvars(),
393 JSScript::isValidOffset(script->regexpsOffset)
394 ? script->regexps()->length
396 JSScript::isValidOffset(script->trynotesOffset)
397 ? script->trynotes()->length
399 JSScript::isValidOffset(script->constOffset)
400 ? script->consts()->length
402 JSScript::isValidOffset(script->globalsOffset)
403 ? script->globals()->length
407 script->getVersion());
411 memcpy(wscript->code, script->code, script->length);
412 wscript->main = wscript->code + (script->main - script->code);
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 *));
421 if (JSScript::isValidOffset(script->regexpsOffset)) {
422 memcpy(wscript->regexps()->vector, script->regexps()->vector,
423 wscript->regexps()->length * sizeof(JSObject *));
425 if (JSScript::isValidOffset(script->trynotesOffset)) {
426 memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
427 wscript->trynotes()->length * sizeof(JSTryNote));
429 if (JSScript::isValidOffset(script->globalsOffset)) {
430 memcpy(wscript->globals()->vector, script->globals()->vector,
431 wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
433 if (script->nClosedArgs + script->nClosedVars != 0)
434 script->copyClosedSlotsTo(wscript);
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));
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;
449 oplen = js_GetVariableBytecodeLength(pc);
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
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;
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.
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;
493 wscript->bindings.clone(cx, &script->bindings);
495 /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
496 FUN_SET_KIND(wfun, JSFUN_INTERPRETED);
497 wfun->u.i.script = wscript;
502 ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
506 if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
509 if (JSID_IS_INT(id)) {
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.
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);
520 *vp = obj->getArgsElement(arg);
522 } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
523 if (!obj->isArgsLengthOverridden())
524 vp->setInt32(obj->getArgsInitialLength());
526 JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
527 const Value &v = obj->getArgsCallee();
528 if (!v.isMagic(JS_ARGS_HOLE)) {
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.
537 if (GET_FUNCTION_PRIVATE(cx, &v.toObject())->needsWrapper()) {
538 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
539 JSMSG_OPTIMIZED_CLOSURE_LEAK);
549 ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
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.
559 if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
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();
567 JSScript *script = fp->functionScript();
568 if (script->usesArguments)
569 fp->canonicalActualArg(arg) = *vp;
574 JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
575 JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
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.
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);
592 args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
595 JS_ASSERT(obj->isNormalArguments());
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))
605 attrs |= JSPROP_ENUMERATE;
606 } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
607 if (obj->isArgsLengthOverridden())
610 if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
613 if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
617 Value undef = UndefinedValue();
618 if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs))
626 args_enumerate(JSContext *cx, JSObject *obj)
628 JS_ASSERT(obj->isNormalArguments());
631 * Trigger reflection in args_resolve using a series of js_LookupProperty
634 int argc = int(obj->getArgsInitialLength());
635 for (int i = -2; i != argc; i++) {
637 ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
639 ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
644 if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
651 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
655 if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
658 if (JSID_IS_INT(id)) {
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.
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))
670 JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
671 if (!obj->isArgsLengthOverridden())
672 vp->setInt32(obj->getArgsInitialLength());
679 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
681 if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
684 if (JSID_IS_INT(id)) {
685 uintN arg = uintN(JSID_TO_INT(id));
686 if (arg < obj->getArgsInitialLength()) {
687 obj->setArgsElement(arg, *vp);
691 JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
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
700 AutoValueRooter tvr(cx);
701 return js_DeleteProperty(cx, obj, id, tvr.addr(), strict) &&
702 js_SetProperty(cx, obj, id, vp, strict);
706 strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
708 JS_ASSERT(obj->isStrictArguments());
712 uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
713 PropertyOp getter = StrictArgGetter;
714 StrictPropertyOp setter = StrictArgSetter;
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))
721 attrs |= JSPROP_ENUMERATE;
722 } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
723 if (obj->isArgsLengthOverridden())
726 if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
727 !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
731 attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
732 getter = CastAsPropertyOp(obj->getThrowTypeError());
733 setter = CastAsStrictPropertyOp(obj->getThrowTypeError());
736 Value undef = UndefinedValue();
737 if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs))
745 strictargs_enumerate(JSContext *cx, JSObject *obj)
747 JS_ASSERT(obj->isStrictArguments());
750 * Trigger reflection in strictargs_resolve using a series of
751 * js_LookupProperty calls.
757 if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
761 if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
765 if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
768 for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
769 if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
777 args_finalize(JSContext *cx, JSObject *obj)
779 cx->free((void *) obj->getArgsData());
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.
791 MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
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");
803 args_trace(JSTracer *trc, JSObject *obj)
805 JS_ASSERT(obj->isArguments());
806 if (obj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
807 JS_ASSERT(!obj->isStrictArguments());
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);
816 MaybeMarkGenerator(trc, obj);
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
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
831 Class js_ArgumentsClass = {
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 */
838 PropertyStub, /* getProperty */
839 StrictPropertyStub, /* setProperty */
841 (JSResolveOp) args_resolve,
843 args_finalize, /* finalize */
844 NULL, /* reserved0 */
845 NULL, /* checkAccess */
847 NULL, /* construct */
848 NULL, /* xdrObject */
849 NULL, /* hasInstance */
850 JS_CLASS_TRACE(args_trace)
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
860 Class StrictArgumentsClass = {
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 */
867 PropertyStub, /* getProperty */
868 StrictPropertyStub, /* setProperty */
869 strictargs_enumerate,
870 reinterpret_cast<JSResolveOp>(strictargs_resolve),
872 args_finalize, /* finalize */
873 NULL, /* reserved0 */
874 NULL, /* checkAccess */
876 NULL, /* construct */
877 NULL, /* xdrObject */
878 NULL, /* hasInstance */
879 JS_CLASS_TRACE(args_trace)
885 * A Declarative Environment object stores its active JSStackFrame pointer in
886 * its private slot, just as Call and Arguments objects do.
888 Class js_DeclEnvClass = {
890 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
891 PropertyStub, /* addProperty */
892 PropertyStub, /* delProperty */
893 PropertyStub, /* getProperty */
894 StrictPropertyStub, /* setProperty */
901 CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp)
903 JS_ASSERT(obj->isCall() || obj->getClass() == &js_DeclEnvClass);
905 const Value &v = *vp;
908 if (IsFunctionObject(v, &funobj)) {
909 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
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.
917 if (fun->needsWrapper()) {
920 JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
922 JSObject *wrapper = WrapEscapingClosure(cx, fp, fun);
925 vp->setObject(*wrapper);
929 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
930 JSMSG_OPTIMIZED_CLOSURE_LEAK);
938 CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
940 return CheckForEscapingClosure(cx, obj, vp);
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.
950 NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject *callee)
952 size_t argsVars = bindings->countArgsAndVars();
953 size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
954 gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
956 JSObject *callobj = js_NewGCObject(cx, kind);
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());
964 /* This must come after callobj->lastProp has been set. */
965 if (!callobj->ensureInstanceReservedSlots(cx, argsVars))
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());
978 callobj->setCallObjCallee(callee);
984 static inline JSObject *
985 NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
987 JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
991 envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
992 envobj->setMap(cx->compartment->emptyDeclEnvShape);
997 js_GetCallObject(JSContext *cx, JSStackFrame *fp)
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();
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);
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
1019 JSAtom *lambdaName =
1020 (fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL;
1022 JSObject *envobj = NewDeclEnvObject(cx, fp);
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()),
1031 JSPROP_PERMANENT | JSPROP_READONLY,
1038 NewCallObject(cx, &fp->fun()->script()->bindings, fp->scopeChain(), &fp->callee());
1042 callobj->setPrivate(fp);
1043 JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
1046 * Push callobj on the top of the scope chain, and make it the
1049 fp->setScopeChainAndCallObj(*callobj);
1053 JSObject * JS_FASTCALL
1054 js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
1056 JS_ASSERT(!js_IsNamedLambda(fun));
1057 JS_ASSERT(scopeChain);
1059 return NewCallObject(cx, &fun->script()->bindings, *scopeChain, callee);
1062 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
1063 0, nanojit::ACCSET_STORE_ANY)
1066 CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
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));
1075 js_PutCallObject(JSContext *cx, JSStackFrame *fp)
1077 JSObject &callobj = fp->callObj();
1080 * Strict mode eval frames have Call objects to put. Normal eval frames
1081 * never put a Call object.
1083 JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval());
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);
1092 JSScript *script = fp->script();
1093 Bindings &bindings = script->bindings;
1095 if (callobj.callIsForEval()) {
1096 JS_ASSERT(script->strictModeCode);
1097 JS_ASSERT(bindings.countArgs() == 0);
1099 /* This could be optimized as below, but keep it simple for now. */
1100 CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
1102 JSFunction *fun = fp->fun();
1103 JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
1104 JS_ASSERT(script == fun->script());
1106 uintN n = bindings.countArgsAndVars();
1108 JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
1110 uint32 nvars = bindings.countVars();
1111 uint32 nargs = bindings.countArgs();
1112 JS_ASSERT(fun->nargs == nargs);
1113 JS_ASSERT(nvars + nargs == n);
1115 JSScript *script = fun->script();
1116 if (script->usesEval
1118 || script->debugMode
1121 CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
1124 * For each arg & var that is closed over, copy it from the stack
1125 * into the call object.
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));
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]);
1141 /* Clear private pointers to fp, which is about to go away (js_Invoke). */
1142 if (js_IsNamedLambda(fun)) {
1143 JSObject *env = callobj.getParent();
1145 JS_ASSERT(env->getClass() == &js_DeclEnvClass);
1146 JS_ASSERT(env->getPrivate() == fp);
1147 env->setPrivate(NULL);
1151 callobj.setPrivate(NULL);
1156 js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv,
1157 uint32 nvars, Value *slots)
1159 JS_ASSERT(callobj->isCall());
1160 JS_ASSERT(!callobj->getPrivate());
1162 uintN n = nargs + nvars;
1164 CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
1169 JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR,
1170 UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
1175 GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1177 JSStackFrame *fp = obj->maybeCallObjStackFrame();
1178 if (fp && !fp->hasOverriddenArgs()) {
1179 JSObject *argsobj = js_GetArgsObject(cx, fp);
1182 vp->setObject(*argsobj);
1184 *vp = obj->getCallObjArguments();
1190 SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1192 if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1193 fp->setOverriddenArgs();
1194 obj->setCallObjArguments(*vp);
1199 GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1201 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1202 uintN i = (uint16) JSID_TO_INT(id);
1204 if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1205 *vp = fp->formalArg(i);
1207 *vp = obj->callObjArg(i);
1212 SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1214 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1215 uintN i = (uint16) JSID_TO_INT(id);
1218 if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1219 argp = &fp->formalArg(i);
1221 argp = &obj->callObjArg(i);
1229 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1231 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1232 uintN i = (uint16) JSID_TO_INT(id);
1234 *vp = obj->getCallObjCallee()->getFlatClosureUpvar(i);
1239 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1241 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1242 uintN i = (uint16) JSID_TO_INT(id);
1244 Value *up = &obj->getCallObjCallee()->getFlatClosureUpvar(i);
1252 GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1254 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1255 uintN i = (uint16) JSID_TO_INT(id);
1257 if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1258 *vp = fp->varSlot(i);
1260 *vp = obj->callObjVar(i);
1266 GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1268 if (!GetCallVar(cx, obj, id, vp))
1271 return CheckForEscapingClosure(cx, obj, vp);
1275 SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
1277 JS_ASSERT(obj->isCall());
1279 JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
1280 uintN i = (uint16) JSID_TO_INT(id);
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.
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");
1298 if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
1299 varp = &fp->varSlot(i);
1301 varp = &obj->callObjVar(i);
1312 js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
1314 Value argcopy = ValueArgToConstRef(arg);
1315 return SetCallArg(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy);
1317 JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, VALUE, 0,
1318 nanojit::ACCSET_STORE_ANY)
1321 js_SetCallVar(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
1323 Value argcopy = ValueArgToConstRef(arg);
1324 return SetCallVar(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy);
1326 JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0,
1327 nanojit::ACCSET_STORE_ANY)
1331 call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
1334 JS_ASSERT(obj->isCall());
1335 JS_ASSERT(!obj->getProto());
1337 if (!JSID_IS_ATOM(id))
1340 JSObject *callee = obj->getCallObjCallee();
1343 JSScript *script = callee->getFunctionPrivate()->script();
1344 JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
1349 * Resolve arguments so that we never store a particular Call object's
1350 * arguments object reference in a Call prototype's |arguments| slot.
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.
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)) {
1367 /* Control flow reaches here only if id was not resolved. */
1372 call_trace(JSTracer *trc, JSObject *obj)
1374 JS_ASSERT(obj->isCall());
1375 if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) {
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
1383 uintN first = JSObject::CALL_RESERVED_SLOTS;
1384 uintN count = fp->script()->bindings.countArgsAndVars();
1386 JS_ASSERT(obj->numSlots() >= first + count);
1387 SetValueRangeToUndefined(obj->getSlots() + first, count);
1390 MaybeMarkGenerator(trc, obj);
1393 JS_PUBLIC_DATA(Class) js_CallClass = {
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 */
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 */
1409 NULL, /* construct */
1410 NULL, /* xdrObject */
1411 NULL, /* hasInstance */
1412 JS_CLASS_TRACE(call_trace)
1416 JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
1418 if (!isFunctionFrame()) {
1423 JSFunction *fun = this->fun();
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.
1431 if (fun->needsWrapper()) {
1432 JSObject *wrapper = WrapEscapingClosure(cx, this, fun);
1435 vp->setObject(*wrapper);
1439 JSObject &funobj = callee();
1440 vp->setObject(funobj);
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.
1447 const Value &thisv = functionThis();
1448 if (thisv.isObject()) {
1449 JS_ASSERT(funobj.getFunctionPrivate() == fun);
1451 if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) {
1452 JSObject *thisp = &thisv.toObject();
1453 JSObject *first_barriered_thisp = NULL;
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.
1461 if (!thisp->isNative())
1464 if (thisp->hasMethodBarrier()) {
1465 const Shape *shape = thisp->nativeLookup(ATOM_TO_JSID(fun->methodAtom()));
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.
1474 * In either case we must allow for the method property
1475 * to have been replaced, or its value overwritten.
1477 if (shape->isMethod() && &shape->methodObject() == &funobj) {
1478 if (!thisp->methodReadBarrier(cx, *shape, vp))
1480 calleeValue().setObject(vp->toObject());
1484 if (shape->hasSlot()) {
1485 Value v = thisp->getSlot(shape->slot);
1488 if (IsFunctionObject(v, &clone) &&
1489 GET_FUNCTION_PRIVATE(cx, clone) == fun &&
1490 clone->hasMethodObj(*thisp)) {
1491 JS_ASSERT(clone != &funobj);
1493 calleeValue().setObject(*clone);
1499 if (!first_barriered_thisp)
1500 first_barriered_thisp = thisp;
1502 } while ((thisp = thisp->getProto()) != NULL);
1504 if (!first_barriered_thisp)
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.
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.
1518 JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent());
1521 newfunobj->setMethodObj(*first_barriered_thisp);
1522 calleeValue().setObject(*newfunobj);
1523 vp->setObject(*newfunobj);
1531 /* Generic function tinyids. */
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 */
1541 fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
1543 if (!JSID_IS_INT(id))
1546 jsint slot = JSID_TO_INT(id);
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).
1555 * This code couples tightly to the attributes for lazyFunctionDataProps[]
1556 * and poisonPillProps[] initializers below, and to js_SetProperty and
1557 * js_HasOwnProperty.
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.
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).
1570 while (!(fun = (JSFunction *)
1571 GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
1572 if (slot != FUN_LENGTH)
1574 obj = obj->getProto();
1579 /* Find fun's top-most activation record. */
1581 for (fp = js_GetTopStackFrame(cx);
1582 fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
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)) {
1598 if (!js_GetArgsValue(cx, fp, vp))
1607 vp->setInt32(fun->nargs);
1611 vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom)
1612 : cx->runtime->emptyString);
1617 if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
1620 if (vp->isObject()) {
1621 JSObject &caller = vp->toObject();
1623 /* Censor the caller if it is from another compartment. */
1624 if (caller.getCompartment() != cx->compartment) {
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);
1638 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1639 if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
1640 *vp = fp->formalArg(slot);
1647 struct LazyFunctionDataProp {
1653 struct PoisonPillProp {
1658 /* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
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},
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 },
1672 fun_enumerate(JSContext *cx, JSObject *obj)
1674 JS_ASSERT(obj->isFunction());
1679 if (!obj->isBoundFunction()) {
1680 id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1681 if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
1685 id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
1686 if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
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))
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))
1707 ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
1710 JSFunction *fun = obj->getFunctionPrivate();
1711 JS_ASSERT(fun->isInterpreted());
1712 JS_ASSERT(!fun->isFunctionPrototype());
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.
1720 JS_ASSERT(!IsInternalFunctionObject(obj));
1721 JS_ASSERT(!obj->isBoundFunction());
1724 * Make the prototype object an instance of Object with the same parent
1725 * as the function object itself.
1727 JSObject *parent = obj->getParent();
1729 if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
1731 proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent);
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.
1743 if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT))
1749 fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
1752 if (!JSID_IS_ATOM(id))
1755 JSFunction *fun = obj->getFunctionPrivate();
1757 if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
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).
1764 * ES5 15.3.4: the non-native function object named Function.prototype
1765 * must not have a .prototype property.
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.
1771 if (fun->isNative() || fun->isFunctionPrototype())
1774 if (!ResolveInterpretedFunctionPrototype(cx, obj))
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)) {
1791 for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
1792 const LazyFunctionDataProp *lfp = &lazyFunctionDataProps[i];
1794 if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset))) {
1795 JS_ASSERT(!IsInternalFunctionObject(obj));
1797 if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
1798 fun_getProperty, StrictPropertyStub,
1799 lfp->attrs, Shape::HAS_SHORTID,
1800 lfp->tinyid, NULL)) {
1808 for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
1809 const PoisonPillProp &p = poisonPillProps[i];
1811 if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, p.atomOffset))) {
1812 JS_ASSERT(!IsInternalFunctionObject(obj));
1815 StrictPropertyOp setter;
1816 uintN attrs = JSPROP_PERMANENT;
1817 if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) {
1818 JSObject *throwTypeError = obj->getThrowTypeError();
1820 getter = CastAsPropertyOp(throwTypeError);
1821 setter = CastAsStrictPropertyOp(throwTypeError);
1822 attrs |= JSPROP_GETTER | JSPROP_SETTER;
1824 getter = fun_getProperty;
1825 setter = StrictPropertyStub;
1828 if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
1830 attrs, Shape::HAS_SHORTID,
1844 /* XXX store parent and proto, if defined */
1846 js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
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 */
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,
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);
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;
1876 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1879 FUN_OBJECT(fun)->clearParent();
1880 FUN_OBJECT(fun)->clearProto();
1883 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
1885 if (!JS_XDRUint32(xdr, &firstword))
1887 if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
1889 if (!JS_XDRUint32(xdr, &flagsword))
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);
1900 if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
1903 if (xdr->mode == JSXDR_DECODE) {
1904 *objp = FUN_OBJECT(fun);
1905 #ifdef CHECK_SCRIPT_OWNER
1906 fun->script()->owner = NULL;
1908 JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
1909 js_CallNewScriptHook(cx, fun->script(), fun);
1915 #else /* !JS_HAS_XDR */
1917 #define js_XDRFunctionObject NULL
1919 #endif /* !JS_HAS_XDR */
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.
1927 fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
1929 while (obj->isFunction()) {
1930 if (!obj->isBoundFunction())
1932 obj = obj->getBoundFunctionTarget();
1935 jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1937 if (!obj->getProperty(cx, id, &pval))
1940 if (pval.isPrimitive()) {
1942 * Throw a runtime error if instanceof is called on a function that
1943 * has a non-object as its .prototype value.
1945 js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
1949 *bp = js_IsDelegate(cx, &pval.toObject(), *v);
1954 fun_trace(JSTracer *trc, JSObject *obj)
1956 /* A newborn function object may have a not yet initialized private slot. */
1957 JSFunction *fun = (JSFunction *) obj->getPrivate();
1962 /* obj is a cloned function object, trace the clone-parent, fun. */
1963 MarkObject(trc, *fun, "private");
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");
1974 MarkString(trc, ATOM_TO_STRING(fun->atom), "atom");
1976 if (fun->isInterpreted() && fun->script())
1977 js_TraceScript(trc, fun->script());
1981 fun_finalize(JSContext *cx, JSObject *obj)
1983 /* Ignore newborn function objects. */
1984 JSFunction *fun = obj->getFunctionPrivate();
1988 /* Cloned function objects may be flat closures with upvars to free. */
1990 if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars())
1991 cx->free((void *) obj->getFlatClosureUpvars());
1996 * Null-check fun->script() because the parser sets interpreted very early.
1998 if (fun->isInterpreted() && fun->script())
1999 js_DestroyScriptFromGC(cx, fun->script());
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.
2007 JS_PUBLIC_DATA(Class) js_FunctionClass = {
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 */
2017 (JSResolveOp)fun_resolve,
2020 NULL, /* reserved0 */
2021 NULL, /* checkAccess */
2023 NULL, /* construct */
2024 js_XDRFunctionObject,
2026 JS_CLASS_TRACE(fun_trace)
2030 fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent)
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,
2042 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
2047 ToSourceCache::Ptr p = cx->compartment->toSourceCache.lookup(fun);
2052 JSString *str = JS_DecompileFunction(cx, fun, indent);
2057 cx->compartment->toSourceCache.put(fun, str);
2063 fun_toString(JSContext *cx, uintN argc, Value *vp)
2065 JS_ASSERT(IsFunctionObject(vp[0]));
2066 uint32_t indent = 0;
2068 if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent))
2071 JSObject *obj = ToObject(cx, &vp[1]);
2075 JSString *str = fun_toStringHelper(cx, obj, indent);
2085 fun_toSource(JSContext *cx, uintN argc, Value *vp)
2087 JS_ASSERT(IsFunctionObject(vp[0]));
2089 JSObject *obj = ToObject(cx, &vp[1]);
2093 JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
2103 js_fun_call(JSContext *cx, uintN argc, Value *vp)
2108 if (!js_IsCallable(fval)) {
2109 if (JSString *str = js_ValueToString(cx, fval)) {
2110 JSAutoByteString bytes(cx, str);
2112 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2113 JSMSG_INCOMPATIBLE_PROTO,
2114 js_Function_str, js_call_str,
2121 Value *argv = vp + 2;
2124 thisv.setUndefined();
2132 /* Allocate stack space for fval, obj, and the args. */
2133 InvokeArgsGuard args;
2134 if (!cx->stack().pushInvokeArgs(cx, argc, &args))
2137 /* Push fval, thisv, and the args. */
2138 args.callee() = fval;
2139 args.thisv() = thisv;
2140 memcpy(args.argv(), argv, argc * sizeof *argv);
2142 bool ok = Invoke(cx, args, 0);
2149 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
2153 if (!js_IsCallable(fval)) {
2154 if (JSString *str = js_ValueToString(cx, fval)) {
2155 JSAutoByteString bytes(cx, str);
2157 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2158 JSMSG_INCOMPATIBLE_PROTO,
2159 js_Function_str, js_apply_str,
2167 if (argc < 2 || vp[3].isNullOrUndefined())
2168 return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
2170 /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
2173 if (!vp[3].isObject()) {
2174 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
2179 * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
2180 * original version of ES5).
2182 JSObject *aobj = &vp[3].toObject();
2184 if (!js_GetLengthProperty(cx, aobj, &length))
2190 uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
2192 InvokeArgsGuard args;
2193 if (!cx->stack().pushInvokeArgs(cx, n, &args))
2196 /* Push fval, obj, and aobj's elements as args. */
2197 args.callee() = fval;
2198 args.thisv() = vp[2];
2201 if (!GetElements(cx, aobj, n, args.argv()))
2205 if (!Invoke(cx, args, 0))
2214 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp);
2219 JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
2220 const Value *args, uintN argslen)
2222 JS_ASSERT(isFunction());
2224 flags |= JSObject::BOUND_FUNCTION;
2225 getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
2226 getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen);
2228 /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
2229 EmptyShape *empty = EmptyShape::create(cx, clasp);
2233 empty->slotSpan += argslen;
2236 if (!ensureInstanceReservedSlots(cx, argslen))
2239 JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
2240 memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
2246 JSObject::getBoundFunctionTarget() const
2248 JS_ASSERT(isFunction());
2249 JS_ASSERT(isBoundFunction());
2251 /* Bound functions abuse |parent| to store their target function. */
2255 inline const js::Value &
2256 JSObject::getBoundFunctionThis() const
2258 JS_ASSERT(isFunction());
2259 JS_ASSERT(isBoundFunction());
2261 return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
2264 inline const js::Value *
2265 JSObject::getBoundFunctionArguments(uintN &argslen) const
2267 JS_ASSERT(isFunction());
2268 JS_ASSERT(isBoundFunction());
2270 argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
2271 JS_ASSERT_IF(argslen > 0, numSlots() >= argslen);
2273 return getSlots() + FUN_CLASS_RESERVED_SLOTS;
2278 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
2280 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
2282 JSObject *obj = &vp[0].toObject();
2283 JS_ASSERT(obj->isFunction());
2284 JS_ASSERT(obj->isBoundFunction());
2288 bool constructing = IsConstructing(vp);
2290 /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
2292 const Value *boundArgs = obj->getBoundFunctionArguments(argslen);
2294 if (argc + argslen > JS_ARGS_LENGTH_MAX) {
2295 js_ReportAllocationOverflow(cx);
2299 /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
2300 JSObject *target = obj->getBoundFunctionTarget();
2302 /* 15.3.4.5.1 step 2. */
2303 const Value &boundThis = obj->getBoundFunctionThis();
2305 InvokeArgsGuard args;
2306 if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
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));
2313 /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
2314 args.callee().setObject(*target);
2317 args.thisv() = boundThis;
2319 if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args, 0))
2330 fun_bind(JSContext *cx, uintN argc, Value *vp)
2333 Value &thisv = vp[1];
2336 if (!js_IsCallable(thisv)) {
2337 if (JSString *str = js_ValueToString(cx, thisv)) {
2338 JSAutoByteString bytes(cx, str);
2340 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2341 JSMSG_INCOMPATIBLE_PROTO,
2342 js_Function_str, "bind", bytes.ptr());
2348 JSObject *target = &thisv.toObject();
2360 if (target->isFunction()) {
2361 uintN nargs = target->getFunctionPrivate()->nargs;
2362 if (nargs > argslen)
2363 length = nargs - argslen;
2366 /* Step 4-6, 10-11. */
2367 JSAtom *name = target->isFunction() ? target->getFunctionPrivate()->atom : NULL;
2369 /* NB: Bound functions abuse |parent| to store their target. */
2371 js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
2372 JSFUN_CONSTRUCTOR, target, name);
2377 Value thisArg = argc >= 1 ? vp[2] : UndefinedValue();
2378 if (!funobj->initBoundFunction(cx, thisArg, args, argslen))
2381 /* Steps 17, 19-21 are handled by fun_resolve. */
2382 /* Step 18 is the default for new functions. */
2385 vp->setObject(*funobj);
2389 static JSFunctionSpec function_methods[] = {
2391 JS_FN(js_toSource_str, fun_toSource, 0,0),
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),
2401 Function(JSContext *cx, uintN argc, Value *vp)
2403 JSObject *obj = NewFunction(cx, NULL);
2407 /* N.B. overwriting callee with return value */
2408 JSObject *parent = vp[0].toObject().getParent();
2409 vp[0].setObject(*obj);
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.
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.).
2421 JSFunction *fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
2422 parent, cx->runtime->atomState.anonymousAtom);
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.
2433 JSStackFrame *caller = js_GetScriptedCaller(cx, NULL);
2435 const char *filename;
2436 JSPrincipals *principals;
2438 JSObject *callee = &JS_CALLEE(cx, vp).toObject();
2439 principals = js_EvalFramePrincipals(cx, callee, caller);
2440 filename = js_ComputeFilename(cx, caller, principals, &lineno);
2447 /* Belt-and-braces: check that the caller has access to parent. */
2448 if (!js_CheckPrincipalsAccess(cx, parent, principals,
2449 CLASS_ATOM(cx, Function))) {
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
2458 if (!js_CheckContentSecurityPolicy(cx, parent)) {
2459 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
2463 Bindings bindings(cx);
2464 AutoBindingsRooter root(cx, bindings);
2466 Value *argv = vp + 2;
2467 uintN n = argc ? argc - 1 : 0;
2469 enum { OK, BAD, BAD_FORMAL } state;
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.
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]);
2488 argv[i].setString(arg);
2491 * Check for overflow. The < test works because the maximum
2492 * JSString length fits in 2 fewer bits than size_t has.
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);
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);
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.
2516 void *mark = JS_ARENA_MARK(&cx->tempPool);
2518 JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
2519 (args_length+1) * sizeof(jschar));
2521 js_ReportOutOfScriptQuota(cx);
2524 jschar *collected_args = cp;
2527 * Concatenate the arguments into the new string, separated by commas.
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);
2534 JS_ARENA_RELEASE(&cx->tempPool, mark);
2537 (void) js_strncpy(cp, arg_chars, arg_length);
2540 /* Add separating comma or terminating 0. */
2541 *cp++ = (i + 1 < n) ? ',' : 0;
2544 /* Initialize a tokenstream that reads from the given string. */
2546 if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion())) {
2547 JS_ARENA_RELEASE(&cx->tempPool, mark);
2551 /* The argument string may be empty or contain no tokens. */
2552 TokenKind tt = ts.getToken();
2553 if (tt != TOK_EOF) {
2556 * Check that it's a name. This also implicitly guards against
2557 * TOK_ERROR, which was already reported.
2563 * Get the atom corresponding to the name from the token
2564 * stream; we're assured at this point that it's a valid
2567 JSAtom *atom = ts.currentToken().t_atom;
2569 /* Check for a duplicate parameter name. */
2570 if (bindings.hasBinding(cx, atom)) {
2571 JSAutoByteString name;
2572 if (!js_AtomToPrintableString(cx, atom, &name)) {
2576 if (!ReportCompileErrorNumber(cx, &ts, NULL,
2577 JSREPORT_WARNING | JSREPORT_STRICT,
2578 JSMSG_DUPLICATE_FORMAL, name.ptr())) {
2585 if (!bindings.addArgument(cx, atom, &dummy)) {
2591 * Get the next token. Stop on end of stream. Otherwise
2592 * insist on a comma, get another name, and iterate.
2597 if (tt != TOK_COMMA)
2605 if (state == BAD_FORMAL && !ts.isError()) {
2607 * Report "malformed formal parameter" iff no illegal char or
2608 * similar scanner error was already reported.
2610 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2614 JS_ARENA_RELEASE(&cx->tempPool, mark);
2621 str = js_ValueToString(cx, argv[argc - 1]);
2624 argv[argc - 1].setString(str);
2626 str = cx->runtime->emptyString;
2629 size_t length = str->length();
2630 const jschar *chars = str->getChars(cx);
2634 return Compiler::compileFunctionBody(cx, fun, principals, &bindings,
2635 chars, length, filename, lineno, cx->findVersion());
2641 IsBuiltinFunctionConstructor(JSFunction *fun)
2643 return fun->maybeNative() == Function;
2647 LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
2650 JSFunction *fun = funobj->getFunctionPrivate();
2651 JS_ASSERT(fun->isInterpreted());
2652 JS_ASSERT(!fun->isFunctionPrototype());
2653 JS_ASSERT(!funobj->isBoundFunction());
2656 jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
2657 const Shape *shape = funobj->nativeLookup(id);
2659 if (!ResolveInterpretedFunctionPrototype(cx, funobj))
2661 shape = funobj->nativeLookup(id);
2663 JS_ASSERT(!shape->configurable());
2664 JS_ASSERT(shape->isDataDescriptor());
2665 JS_ASSERT(shape->hasSlot());
2666 JS_ASSERT(!shape->isMethod());
2670 } /* namespace js */
2673 ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
2675 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
2676 JSMSG_THROW_TYPE_ERROR);
2681 js_InitFunctionClass(JSContext *cx, JSObject *obj)
2683 JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
2684 NULL, function_methods, NULL, NULL);
2688 JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
2691 fun->flags |= JSFUN_PROTOTYPE;
2693 JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT);
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;
2702 fun->u.i.script = script;
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,
2709 if (!throwTypeError)
2712 JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR,
2713 ObjectValue(*throwTypeError)));
2720 js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
2721 uintN flags, JSObject *parent, JSAtom *atom)
2726 JS_ASSERT(funobj->isFunction());
2727 funobj->setParent(parent);
2729 funobj = NewFunction(cx, parent);
2733 JS_ASSERT(!funobj->getPrivate());
2734 fun = (JSFunction *) funobj;
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) {
2741 JS_ASSERT(nargs == 0);
2742 fun->u.i.skipmin = 0;
2743 fun->u.i.wrapper = false;
2744 fun->u.i.script = NULL;
2746 fun->u.n.clasp = NULL;
2747 if (flags & JSFUN_TRCINFO) {
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;
2754 fun->u.n.trcinfo = NULL;
2757 fun->u.n.native = native;
2758 fun->u.n.trcinfo = NULL;
2760 JS_ASSERT(fun->u.n.native);
2764 /* Set private to self to indicate non-cloned fully initialized function. */
2765 FUN_OBJECT(fun)->setPrivate(fun);
2769 JSObject * JS_FASTCALL
2770 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
2777 if (cx->compartment == fun->compartment()) {
2779 * The cloned function object does not need the extra JSFunction members
2780 * beyond JSObject as it points to fun via the private slot.
2782 clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
2785 clone->setPrivate(fun);
2788 * Across compartments we have to deep copy JSFunction and clone the
2789 * script (for interpreted functions).
2791 clone = NewFunction(cx, parent);
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;
2803 JS_ASSERT(script->compartment == fun->compartment());
2804 JS_ASSERT(script->compartment != cx->compartment);
2806 cfun->u.i.script = js_CloneScript(cx, script);
2807 if (!cfun->u.i.script)
2809 #ifdef CHECK_SCRIPT_OWNER
2810 cfun->script()->owner = NULL;
2812 js_CallNewScriptHook(cx, cfun->script(), cfun);
2819 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0,
2820 nanojit::ACCSET_STORE_ANY)
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
2828 JSObject * JS_FASTCALL
2829 js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
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());
2837 JSObject *closure = CloneFunctionObject(cx, fun, scopeChain);
2841 uint32 nslots = fun->script()->bindings.countUpvars();
2845 Value *upvars = (Value *) cx->malloc(nslots * sizeof(Value));
2849 closure->setFlatClosureUpvars(upvars);
2853 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
2854 CONTEXT, FUNCTION, OBJECT, 0, nanojit::ACCSET_STORE_ANY)
2857 js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
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.
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.
2868 VOUCH_DOES_NOT_REQUIRE_STACK();
2869 JSObject *scopeChain = &cx->fp()->scopeChain();
2871 JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain);
2872 if (!closure || !fun->script()->bindings.hasUpvars())
2875 Value *upvars = closure->getFlatClosureUpvars();
2876 uintN level = fun->u.i.script->staticLevel;
2877 JSUpvarArray *uva = fun->script()->upvars();
2879 for (uint32 i = 0, n = uva->length; i < n; i++)
2880 upvars[i] = GetUpvar(cx, level, uva->vector[i]);
2886 js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
2888 JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
2889 JS_ASSERT(!cx->fp()->fun()->optimizedClosure());
2890 JS_ASSERT(FUN_FLAT_CLOSURE(fun));
2892 return WrapEscapingClosure(cx, cx->fp(), fun);
2896 js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
2897 uintN nargs, uintN attrs)
2900 StrictPropertyOp sop;
2903 if (attrs & JSFUN_STUB_GSOPS) {
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
2910 attrs &= ~JSFUN_STUB_GSOPS;
2912 sop = StrictPropertyStub;
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.
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
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).
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.
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.
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.
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).
2956 * FIXME: bug 611190.
2958 bool wasDelegate = obj->isDelegate();
2960 fun = js_NewFunction(cx, NULL, native, nargs,
2961 attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
2963 JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
2967 if (!wasDelegate && obj->isDelegate())
2968 obj->clearDelegate();
2970 if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
2975 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2976 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2980 js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags)
2983 if (!IsFunctionObject(*vp, &funobj)) {
2984 js_ReportIsNotFunction(cx, vp, flags);
2987 return GET_FUNCTION_PRIVATE(cx, funobj);
2991 js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags)
2994 if (!IsFunctionObject(*vp, &funobj)) {
2995 js_ReportIsNotFunction(cx, vp, flags);
3003 js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags)
3005 if (vp->isObject()) {
3006 JSObject *callable = &vp->toObject();
3007 if (callable->isCallable())
3011 js_ReportIsNotFunction(cx, vp, flags);
3016 js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
3018 const char *name = NULL, *source = NULL;
3019 AutoValueRooter tvr(cx);
3020 uintN error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
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.
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.
3035 ptrdiff_t spindex = 0;
3037 FrameRegsIter i(cx);
3038 while (!i.done() && !i.pc())
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;
3049 spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
3051 js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);