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"
66 #include "jspropertytree.h"
73 #include "jsstaticcheck.h"
81 # include "jsxdrapi.h"
85 #include "methodjit/MethodJIT.h"
88 #include "jsatominlines.h"
89 #include "jscntxtinlines.h"
90 #include "jsfuninlines.h"
91 #include "jsinterpinlines.h"
92 #include "jsobjinlines.h"
93 #include "jsscriptinlines.h"
96 using namespace js::gc
;
99 JSObject::getThrowTypeError() const
101 return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR
).toObject();
105 js_GetArgsValue(JSContext
*cx
, JSStackFrame
*fp
, Value
*vp
)
109 if (fp
->hasOverriddenArgs()) {
110 JS_ASSERT(fp
->hasCallObj());
111 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
112 return fp
->callObj().getProperty(cx
, id
, vp
);
114 argsobj
= js_GetArgsObject(cx
, fp
);
117 vp
->setObject(*argsobj
);
122 js_GetArgsProperty(JSContext
*cx
, JSStackFrame
*fp
, jsid id
, Value
*vp
)
124 JS_ASSERT(fp
->isFunctionFrame());
126 if (fp
->hasOverriddenArgs()) {
127 JS_ASSERT(fp
->hasCallObj());
129 jsid argumentsid
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
131 if (!fp
->callObj().getProperty(cx
, argumentsid
, &v
))
135 if (v
.isPrimitive()) {
136 obj
= js_ValueToNonNullObject(cx
, v
);
142 return obj
->getProperty(cx
, id
, vp
);
146 if (JSID_IS_INT(id
)) {
147 uint32 arg
= uint32(JSID_TO_INT(id
));
148 JSObject
*argsobj
= fp
->maybeArgsObj();
149 if (arg
< fp
->numActualArgs()) {
151 if (argsobj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
152 return argsobj
->getProperty(cx
, id
, vp
);
154 *vp
= fp
->canonicalActualArg(arg
);
157 * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
158 * storage between the formal parameter and arguments[k] for all
159 * fp->argc <= k && k < fp->fun->nargs. For example, in
161 * function f(x) { x = 42; return arguments[0]; }
164 * the call to f should return undefined, not 42. If fp->argsobj
165 * is null at this point, as it would be in the example, return
169 return argsobj
->getProperty(cx
, id
, vp
);
171 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
172 JSObject
*argsobj
= fp
->maybeArgsObj();
173 if (argsobj
&& argsobj
->isArgsLengthOverridden())
174 return argsobj
->getProperty(cx
, id
, vp
);
175 vp
->setInt32(fp
->numActualArgs());
181 NewArguments(JSContext
*cx
, JSObject
*parent
, uint32 argc
, JSObject
&callee
)
184 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
187 JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS
== 2);
188 JSObject
*argsobj
= js_NewGCObject(cx
, FINALIZE_OBJECT2
);
192 ArgumentsData
*data
= (ArgumentsData
*)
193 cx
->malloc(offsetof(ArgumentsData
, slots
) + argc
* sizeof(Value
));
196 SetValueRangeToUndefined(data
->slots
, argc
);
198 /* Can't fail from here on, so initialize everything in argsobj. */
199 argsobj
->init(cx
, callee
.getFunctionPrivate()->inStrictMode()
200 ? &StrictArgumentsClass
201 : &js_ArgumentsClass
,
202 proto
, parent
, NULL
, false);
204 argsobj
->setMap(cx
->runtime
->emptyArgumentsShape
);
206 argsobj
->setArgsLength(argc
);
207 argsobj
->setArgsData(data
);
208 data
->callee
.setObject(callee
);
213 struct STATIC_SKIP_INFERENCE PutArg
215 PutArg(Value
*dst
) : dst(dst
) {}
217 void operator()(uintN
, Value
*src
) {
218 if (!dst
->isMagic(JS_ARGS_HOLE
))
225 js_GetArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
228 * We must be in a function activation; the function must be lightweight
229 * or else fp must have a variable object.
231 JS_ASSERT_IF(fp
->fun()->isHeavyweight(), fp
->hasCallObj());
233 while (fp
->isEvalOrDebuggerFrame())
236 /* Create an arguments object for fp only if it lacks one. */
237 if (fp
->hasArgsObj())
238 return &fp
->argsObj();
240 /* Compute the arguments object's parent slot from fp's scope chain. */
241 JSObject
*global
= fp
->scopeChain().getGlobal();
242 JSObject
*argsobj
= NewArguments(cx
, global
, fp
->numActualArgs(), fp
->callee());
247 * Strict mode functions have arguments objects that copy the initial
248 * actual parameter values. It is the caller's responsibility to get the
249 * arguments object before any parameters are modified! (The emitter
250 * ensures this by synthesizing an arguments access at the start of any
251 * strict mode function that contains an assignment to a parameter, or
252 * that calls eval.) Non-strict mode arguments use the frame pointer to
253 * retrieve up-to-date parameter values.
255 if (argsobj
->isStrictArguments())
256 fp
->forEachCanonicalActualArg(PutArg(argsobj
->getArgsData()->slots
));
258 argsobj
->setPrivate(fp
);
260 fp
->setArgsObj(*argsobj
);
265 js_PutArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
267 JSObject
&argsobj
= fp
->argsObj();
268 if (argsobj
.isNormalArguments()) {
269 JS_ASSERT(argsobj
.getPrivate() == fp
);
270 fp
->forEachCanonicalActualArg(PutArg(argsobj
.getArgsData()->slots
));
271 argsobj
.setPrivate(NULL
);
273 JS_ASSERT(!argsobj
.getPrivate());
281 * Traced versions of js_GetArgsObject and js_PutArgsObject.
283 JSObject
* JS_FASTCALL
284 js_NewArgumentsOnTrace(JSContext
*cx
, JSObject
*parent
, uint32 argc
, JSObject
*callee
)
286 JSObject
*argsobj
= NewArguments(cx
, parent
, argc
, *callee
);
290 if (argsobj
->isStrictArguments()) {
292 * Strict mode callers must copy arguments into the created arguments
293 * object. The trace-JITting code is in TraceRecorder::newArguments.
295 JS_ASSERT(!argsobj
->getPrivate());
297 argsobj
->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE
);
302 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_NewArgumentsOnTrace
, CONTEXT
, OBJECT
, UINT32
, OBJECT
,
303 0, nanojit::ACCSET_STORE_ANY
)
305 /* FIXME change the return type to void. */
307 js_PutArgumentsOnTrace(JSContext
*cx
, JSObject
*argsobj
, Value
*args
)
309 JS_ASSERT(argsobj
->isNormalArguments());
310 JS_ASSERT(argsobj
->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE
);
313 * TraceRecorder::putActivationObjects builds a single, contiguous array of
314 * the arguments, regardless of whether #actuals > #formals so there is no
315 * need to worry about actual vs. formal arguments.
317 Value
*srcend
= args
+ argsobj
->getArgsInitialLength();
318 Value
*dst
= argsobj
->getArgsData()->slots
;
319 for (Value
*src
= args
; src
!= srcend
; ++src
, ++dst
) {
320 if (!dst
->isMagic(JS_ARGS_HOLE
))
324 argsobj
->setPrivate(NULL
);
327 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_PutArgumentsOnTrace
, CONTEXT
, OBJECT
, VALUEPTR
, 0,
328 nanojit::ACCSET_STORE_ANY
)
330 #endif /* JS_TRACER */
333 args_delProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
335 JS_ASSERT(obj
->isArguments());
337 if (JSID_IS_INT(id
)) {
338 uintN arg
= uintN(JSID_TO_INT(id
));
339 if (arg
< obj
->getArgsInitialLength())
340 obj
->setArgsElement(arg
, MagicValue(JS_ARGS_HOLE
));
341 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
342 obj
->setArgsLengthOverridden();
343 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
)) {
344 obj
->setArgsCallee(MagicValue(JS_ARGS_HOLE
));
349 static JS_REQUIRES_STACK JSObject
*
350 WrapEscapingClosure(JSContext
*cx
, JSStackFrame
*fp
, JSFunction
*fun
)
352 JS_ASSERT(fun
->optimizedClosure());
353 JS_ASSERT(!fun
->u
.i
.wrapper
);
356 * We do not attempt to reify Call and Block objects on demand for outer
357 * scopes. This could be done (see the "v8" patch in bug 494235) but it is
358 * fragile in the face of ongoing compile-time optimization. Instead, the
359 * _DBG* opcodes used by wrappers created here must cope with unresolved
360 * upvars and throw them as reference errors. Caveat debuggers!
362 JSObject
*scopeChain
= GetScopeChain(cx
, fp
);
366 JSObject
*wfunobj
= NewFunction(cx
, scopeChain
);
369 AutoObjectRooter
tvr(cx
, wfunobj
);
371 JSFunction
*wfun
= (JSFunction
*) wfunobj
;
372 wfunobj
->setPrivate(wfun
);
373 wfun
->nargs
= fun
->nargs
;
374 wfun
->flags
= fun
->flags
| JSFUN_HEAVYWEIGHT
;
375 wfun
->u
.i
.skipmin
= fun
->u
.i
.skipmin
;
376 wfun
->u
.i
.wrapper
= true;
377 wfun
->u
.i
.script
= NULL
;
378 wfun
->atom
= fun
->atom
;
380 JSScript
*script
= fun
->script();
381 jssrcnote
*snbase
= script
->notes();
382 jssrcnote
*sn
= snbase
;
383 while (!SN_IS_TERMINATOR(sn
))
385 uintN nsrcnotes
= (sn
- snbase
) + 1;
387 /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
388 JSScript
*wscript
= JSScript::NewScript(cx
, script
->length
, nsrcnotes
,
389 script
->atomMap
.length
,
390 JSScript::isValidOffset(script
->objectsOffset
)
391 ? script
->objects()->length
393 script
->bindings
.countUpvars(),
394 JSScript::isValidOffset(script
->regexpsOffset
)
395 ? script
->regexps()->length
397 JSScript::isValidOffset(script
->trynotesOffset
)
398 ? script
->trynotes()->length
400 JSScript::isValidOffset(script
->constOffset
)
401 ? script
->consts()->length
403 JSScript::isValidOffset(script
->globalsOffset
)
404 ? script
->globals()->length
407 script
->nClosedVars
);
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 wscript
->setVersion(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
, 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.
556 if (JS_ON_TRACE(cx
)) {
562 if (!InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
565 if (JSID_IS_INT(id
)) {
566 uintN arg
= uintN(JSID_TO_INT(id
));
567 if (arg
< obj
->getArgsInitialLength()) {
568 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
570 JSScript
*script
= fp
->functionScript();
571 if (script
->usesArguments
)
572 fp
->canonicalActualArg(arg
) = *vp
;
577 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
) ||
578 JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
));
582 * For simplicity we use delete/set to replace the property with one
583 * backed by the default Object getter and setter. Note that we rely on
584 * args_delProperty to clear the corresponding reserved slot so the GC can
587 AutoValueRooter
tvr(cx
);
588 return js_DeleteProperty(cx
, obj
, id
, tvr
.addr(), false) &&
589 js_SetProperty(cx
, obj
, id
, vp
, false);
593 args_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
596 JS_ASSERT(obj
->isNormalArguments());
600 uintN attrs
= JSPROP_SHARED
| JSPROP_SHADOWABLE
;
601 if (JSID_IS_INT(id
)) {
602 uint32 arg
= uint32(JSID_TO_INT(id
));
603 if (arg
>= obj
->getArgsInitialLength() || obj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
606 attrs
|= JSPROP_ENUMERATE
;
607 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
608 if (obj
->isArgsLengthOverridden())
611 if (!JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
))
614 if (obj
->getArgsCallee().isMagic(JS_ARGS_HOLE
))
618 Value undef
= UndefinedValue();
619 if (!js_DefineProperty(cx
, obj
, id
, &undef
, ArgGetter
, ArgSetter
, attrs
))
627 args_enumerate(JSContext
*cx
, JSObject
*obj
)
629 JS_ASSERT(obj
->isNormalArguments());
632 * Trigger reflection in args_resolve using a series of js_LookupProperty
635 int argc
= int(obj
->getArgsInitialLength());
636 for (int i
= -2; i
!= argc
; i
++) {
638 ? ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)
640 ? ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
)
645 if (!js_LookupProperty(cx
, obj
, id
, &pobj
, &prop
))
652 StrictArgGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
656 if (!InstanceOf(cx
, obj
, &StrictArgumentsClass
, NULL
))
659 if (JSID_IS_INT(id
)) {
661 * arg can exceed the number of arguments if a script changed the
662 * prototype to point to another Arguments object with a bigger argc.
664 uintN arg
= uintN(JSID_TO_INT(id
));
665 if (arg
< obj
->getArgsInitialLength()) {
666 const Value
&v
= obj
->getArgsElement(arg
);
667 if (!v
.isMagic(JS_ARGS_HOLE
))
671 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
));
672 if (!obj
->isArgsLengthOverridden())
673 vp
->setInt32(obj
->getArgsInitialLength());
679 StrictArgSetter(JSContext
*cx
, JSObject
*obj
, jsid id
, 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(), true) &&
702 js_SetProperty(cx
, obj
, id
, vp
, true);
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 PropertyOp 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
= setter
= CastAsPropertyOp(obj
->getThrowTypeError());
735 Value undef
= UndefinedValue();
736 if (!js_DefineProperty(cx
, obj
, id
, &undef
, getter
, setter
, attrs
))
744 strictargs_enumerate(JSContext
*cx
, JSObject
*obj
)
746 JS_ASSERT(obj
->isStrictArguments());
749 * Trigger reflection in strictargs_resolve using a series of
750 * js_LookupProperty calls.
756 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
), &pobj
, &prop
))
760 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
), &pobj
, &prop
))
764 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.callerAtom
), &pobj
, &prop
))
767 for (uint32 i
= 0, argc
= obj
->getArgsInitialLength(); i
< argc
; i
++) {
768 if (!js_LookupProperty(cx
, obj
, INT_TO_JSID(i
), &pobj
, &prop
))
776 args_finalize(JSContext
*cx
, JSObject
*obj
)
778 cx
->free((void *) obj
->getArgsData());
782 * If a generator's arguments or call object escapes, and the generator frame
783 * is not executing, the generator object needs to be marked because it is not
784 * otherwise reachable. An executing generator is rooted by its invocation. To
785 * distinguish the two cases (which imply different access paths to the
786 * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
787 * set on the JSStackFrame kept in the generator object's JSGenerator.
790 MaybeMarkGenerator(JSTracer
*trc
, JSObject
*obj
)
792 #if JS_HAS_GENERATORS
793 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
794 if (fp
&& fp
->isFloatingGenerator()) {
795 JSObject
*genobj
= js_FloatingFrameToGenerator(fp
)->obj
;
796 MarkObject(trc
, *genobj
, "generator object");
802 args_trace(JSTracer
*trc
, JSObject
*obj
)
804 JS_ASSERT(obj
->isArguments());
805 if (obj
->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE
) {
806 JS_ASSERT(!obj
->isStrictArguments());
810 ArgumentsData
*data
= obj
->getArgsData();
811 if (data
->callee
.isObject())
812 MarkObject(trc
, data
->callee
.toObject(), js_callee_str
);
813 MarkValueRange(trc
, obj
->getArgsInitialLength(), data
->slots
, js_arguments_str
);
815 MaybeMarkGenerator(trc
, obj
);
819 * The Arguments classes aren't initialized via js_InitClass, because arguments
820 * objects have the initial value of Object.prototype as their [[Prototype]].
821 * However, Object.prototype.toString.call(arguments) === "[object Arguments]"
822 * per ES5 (although not ES3), so the class name is "Arguments" rather than
825 * The JSClass functions below collaborate to lazily reflect and synchronize
826 * actual argument values, argument count, and callee function object stored
827 * in a JSStackFrame with their corresponding property values in the frame's
830 Class js_ArgumentsClass
= {
832 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
833 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
834 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
835 PropertyStub
, /* addProperty */
837 PropertyStub
, /* getProperty */
838 PropertyStub
, /* setProperty */
840 (JSResolveOp
) args_resolve
,
842 args_finalize
, /* finalize */
843 NULL
, /* reserved0 */
844 NULL
, /* checkAccess */
846 NULL
, /* construct */
847 NULL
, /* xdrObject */
848 NULL
, /* hasInstance */
849 JS_CLASS_TRACE(args_trace
)
855 * Strict mode arguments is significantly less magical than non-strict mode
856 * arguments, so it is represented by a different class while sharing some
859 Class StrictArgumentsClass
= {
861 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
862 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
863 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
864 PropertyStub
, /* addProperty */
866 PropertyStub
, /* getProperty */
867 PropertyStub
, /* setProperty */
868 strictargs_enumerate
,
869 reinterpret_cast<JSResolveOp
>(strictargs_resolve
),
871 args_finalize
, /* finalize */
872 NULL
, /* reserved0 */
873 NULL
, /* checkAccess */
875 NULL
, /* construct */
876 NULL
, /* xdrObject */
877 NULL
, /* hasInstance */
878 JS_CLASS_TRACE(args_trace
)
884 * A Declarative Environment object stores its active JSStackFrame pointer in
885 * its private slot, just as Call and Arguments objects do.
887 Class js_DeclEnvClass
= {
889 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
890 PropertyStub
, /* addProperty */
891 PropertyStub
, /* delProperty */
892 PropertyStub
, /* getProperty */
893 PropertyStub
, /* setProperty */
900 CheckForEscapingClosure(JSContext
*cx
, JSObject
*obj
, Value
*vp
)
902 JS_ASSERT(obj
->isCall() || obj
->getClass() == &js_DeclEnvClass
);
904 const Value
&v
= *vp
;
907 if (IsFunctionObject(v
, &funobj
)) {
908 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
911 * Any escaping null or flat closure that reaches above itself or
912 * contains nested functions that reach above it must be wrapped.
913 * We can wrap only when this Call or Declarative Environment obj
914 * still has an active stack frame associated with it.
916 if (fun
->needsWrapper()) {
919 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
921 JSObject
*wrapper
= WrapEscapingClosure(cx
, fp
, fun
);
924 vp
->setObject(*wrapper
);
928 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
929 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
937 CalleeGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
939 return CheckForEscapingClosure(cx
, obj
, vp
);
945 * Construct a call object for the given bindings. The callee is the function
946 * on behalf of which the call object is being created.
949 NewCallObject(JSContext
*cx
, Bindings
*bindings
, JSObject
&scopeChain
, JSObject
*callee
)
951 size_t argsVars
= bindings
->countArgsAndVars();
952 size_t slots
= JSObject::CALL_RESERVED_SLOTS
+ argsVars
;
953 gc::FinalizeKind kind
= gc::GetGCObjectKind(slots
);
955 JSObject
*callobj
= js_NewGCObject(cx
, kind
);
959 /* Init immediately to avoid GC seeing a half-init'ed object. */
960 callobj
->init(cx
, &js_CallClass
, NULL
, &scopeChain
, NULL
, false);
961 callobj
->setMap(bindings
->lastShape());
963 /* This must come after callobj->lastProp has been set. */
964 if (!callobj
->ensureInstanceReservedSlots(cx
, argsVars
))
968 for (Shape::Range r
= callobj
->lastProp
; !r
.empty(); r
.popFront()) {
969 const Shape
&s
= r
.front();
970 if (s
.slot
!= SHAPE_INVALID_SLOT
) {
971 JS_ASSERT(s
.slot
+ 1 == callobj
->slotSpan());
977 callobj
->setCallObjCallee(callee
);
983 static inline JSObject
*
984 NewDeclEnvObject(JSContext
*cx
, JSStackFrame
*fp
)
986 JSObject
*envobj
= js_NewGCObject(cx
, FINALIZE_OBJECT2
);
990 envobj
->init(cx
, &js_DeclEnvClass
, NULL
, &fp
->scopeChain(), fp
, false);
991 envobj
->setMap(cx
->runtime
->emptyDeclEnvShape
);
996 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
)
998 /* Create a call object for fp only if it lacks one. */
999 JS_ASSERT(fp
->isFunctionFrame());
1000 if (fp
->hasCallObj())
1001 return &fp
->callObj();
1004 /* A call object should be a frame's outermost scope chain element. */
1005 Class
*clasp
= fp
->scopeChain().getClass();
1006 if (clasp
== &js_WithClass
|| clasp
== &js_BlockClass
)
1007 JS_ASSERT(fp
->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx
, fp
));
1008 else if (clasp
== &js_CallClass
)
1009 JS_ASSERT(fp
->scopeChain().getPrivate() != fp
);
1013 * Create the call object, using the frame's enclosing scope as its
1014 * parent, and link the call to its stack frame. For a named function
1015 * expression Call's parent points to an environment object holding
1018 JSAtom
*lambdaName
=
1019 (fp
->fun()->flags
& JSFUN_LAMBDA
) ? fp
->fun()->atom
: NULL
;
1021 JSObject
*envobj
= NewDeclEnvObject(cx
, fp
);
1025 /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
1026 fp
->setScopeChainNoCallObj(*envobj
);
1027 if (!js_DefineNativeProperty(cx
, &fp
->scopeChain(), ATOM_TO_JSID(lambdaName
),
1028 ObjectValue(fp
->callee()),
1030 JSPROP_PERMANENT
| JSPROP_READONLY
,
1037 NewCallObject(cx
, &fp
->fun()->script()->bindings
, fp
->scopeChain(), &fp
->callee());
1041 callobj
->setPrivate(fp
);
1042 JS_ASSERT(fp
->fun() == fp
->callee().getFunctionPrivate());
1045 * Push callobj on the top of the scope chain, and make it the
1048 fp
->setScopeChainAndCallObj(*callobj
);
1052 JSObject
* JS_FASTCALL
1053 js_CreateCallObjectOnTrace(JSContext
*cx
, JSFunction
*fun
, JSObject
*callee
, JSObject
*scopeChain
)
1055 JS_ASSERT(!js_IsNamedLambda(fun
));
1056 JS_ASSERT(scopeChain
);
1058 return NewCallObject(cx
, &fun
->script()->bindings
, *scopeChain
, callee
);
1061 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CreateCallObjectOnTrace
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
,
1062 0, nanojit::ACCSET_STORE_ANY
)
1065 CopyValuesToCallObject(JSObject
&callobj
, uintN nargs
, Value
*argv
, uintN nvars
, Value
*slots
)
1067 JS_ASSERT(callobj
.numSlots() >= JSObject::CALL_RESERVED_SLOTS
+ nargs
+ nvars
);
1068 Value
*base
= callobj
.getSlots() + JSObject::CALL_RESERVED_SLOTS
;
1069 memcpy(base
, argv
, nargs
* sizeof(Value
));
1070 memcpy(base
+ nargs
, slots
, nvars
* sizeof(Value
));
1074 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1076 JSObject
&callobj
= fp
->callObj();
1079 * Strict mode eval frames have Call objects to put. Normal eval frames
1080 * never put a Call object.
1082 JS_ASSERT(fp
->isEvalFrame() == callobj
.callIsForEval());
1084 /* Get the arguments object to snapshot fp's actual argument values. */
1085 if (fp
->hasArgsObj()) {
1086 if (!fp
->hasOverriddenArgs())
1087 callobj
.setCallObjArguments(ObjectValue(fp
->argsObj()));
1088 js_PutArgsObject(cx
, fp
);
1091 JSScript
*script
= fp
->script();
1092 Bindings
&bindings
= script
->bindings
;
1094 if (callobj
.callIsForEval()) {
1095 JS_ASSERT(script
->strictModeCode
);
1096 JS_ASSERT(bindings
.countArgs() == 0);
1098 /* This could be optimized as below, but keep it simple for now. */
1099 CopyValuesToCallObject(callobj
, 0, NULL
, bindings
.countVars(), fp
->slots());
1101 JSFunction
*fun
= fp
->fun();
1102 JS_ASSERT(fun
== callobj
.getCallObjCalleeFunction());
1103 JS_ASSERT(script
== fun
->script());
1105 uintN n
= bindings
.countArgsAndVars();
1107 JS_ASSERT(JSObject::CALL_RESERVED_SLOTS
+ n
<= callobj
.numSlots());
1109 uint32 nvars
= bindings
.countVars();
1110 uint32 nargs
= bindings
.countArgs();
1111 JS_ASSERT(fun
->nargs
== nargs
);
1112 JS_ASSERT(nvars
+ nargs
== n
);
1114 JSScript
*script
= fun
->script();
1115 if (script
->usesEval
1117 || script
->debugMode
1120 CopyValuesToCallObject(callobj
, nargs
, fp
->formalArgs(), nvars
, fp
->slots());
1123 * For each arg & var that is closed over, copy it from the stack
1124 * into the call object.
1126 uint32 nclosed
= script
->nClosedArgs
;
1127 for (uint32 i
= 0; i
< nclosed
; i
++) {
1128 uint32 e
= script
->getClosedArg(i
);
1129 callobj
.setSlot(JSObject::CALL_RESERVED_SLOTS
+ e
, fp
->formalArg(e
));
1132 nclosed
= script
->nClosedVars
;
1133 for (uint32 i
= 0; i
< nclosed
; i
++) {
1134 uint32 e
= script
->getClosedVar(i
);
1135 callobj
.setSlot(JSObject::CALL_RESERVED_SLOTS
+ nargs
+ e
, fp
->slots()[e
]);
1140 /* Clear private pointers to fp, which is about to go away (js_Invoke). */
1141 if (js_IsNamedLambda(fun
)) {
1142 JSObject
*env
= callobj
.getParent();
1144 JS_ASSERT(env
->getClass() == &js_DeclEnvClass
);
1145 JS_ASSERT(env
->getPrivate() == fp
);
1146 env
->setPrivate(NULL
);
1150 callobj
.setPrivate(NULL
);
1155 js_PutCallObjectOnTrace(JSContext
*cx
, JSObject
*callobj
, uint32 nargs
, Value
*argv
,
1156 uint32 nvars
, Value
*slots
)
1158 JS_ASSERT(callobj
->isCall());
1159 JS_ASSERT(!callobj
->getPrivate());
1161 uintN n
= nargs
+ nvars
;
1163 CopyValuesToCallObject(*callobj
, nargs
, argv
, nvars
, slots
);
1168 JS_DEFINE_CALLINFO_6(extern, BOOL
, js_PutCallObjectOnTrace
, CONTEXT
, OBJECT
, UINT32
, VALUEPTR
,
1169 UINT32
, VALUEPTR
, 0, nanojit::ACCSET_STORE_ANY
)
1174 GetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1176 JSStackFrame
*fp
= obj
->maybeCallObjStackFrame();
1177 if (fp
&& !fp
->hasOverriddenArgs()) {
1178 JSObject
*argsobj
= js_GetArgsObject(cx
, fp
);
1181 vp
->setObject(*argsobj
);
1183 *vp
= obj
->getCallObjArguments();
1189 SetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1191 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1192 fp
->setOverriddenArgs();
1193 obj
->setCallObjArguments(*vp
);
1198 GetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1200 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1201 uintN i
= (uint16
) JSID_TO_INT(id
);
1203 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1204 *vp
= fp
->formalArg(i
);
1206 *vp
= obj
->callObjArg(i
);
1211 SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1213 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1214 uintN i
= (uint16
) JSID_TO_INT(id
);
1217 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1218 argp
= &fp
->formalArg(i
);
1220 argp
= &obj
->callObjArg(i
);
1228 GetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1230 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1231 uintN i
= (uint16
) JSID_TO_INT(id
);
1233 *vp
= obj
->getCallObjCallee()->getFlatClosureUpvar(i
);
1238 SetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1240 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1241 uintN i
= (uint16
) JSID_TO_INT(id
);
1243 Value
*up
= &obj
->getCallObjCallee()->getFlatClosureUpvar(i
);
1251 GetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1253 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1254 uintN i
= (uint16
) JSID_TO_INT(id
);
1256 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1257 *vp
= fp
->varSlot(i
);
1259 *vp
= obj
->callObjVar(i
);
1265 GetCallVarChecked(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1267 if (!GetCallVar(cx
, obj
, id
, vp
))
1270 return CheckForEscapingClosure(cx
, obj
, vp
);
1274 SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1276 JS_ASSERT(obj
->isCall());
1278 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1279 uintN i
= (uint16
) JSID_TO_INT(id
);
1282 * As documented in TraceRecorder::attemptTreeCall(), when recording an
1283 * inner tree call, the recorder assumes the inner tree does not mutate
1284 * any tracked upvars. The abort here is a pessimistic precaution against
1285 * bug 620662, where an inner tree setting a closed stack variable in an
1286 * outer tree is illegal, and runtime would fall off trace.
1289 TraceMonitor
*tm
= &JS_TRACE_MONITOR(cx
);
1290 if (tm
->recorder
&& tm
->tracecx
)
1291 AbortRecording(cx
, "upvar write in nested tree");
1295 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1296 varp
= &fp
->varSlot(i
);
1298 varp
= &obj
->callObjVar(i
);
1309 js_SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1311 Value argcopy
= ValueArgToConstRef(arg
);
1312 return SetCallArg(cx
, obj
, slotid
, &argcopy
);
1314 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallArg
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1315 nanojit::ACCSET_STORE_ANY
)
1318 js_SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1320 Value argcopy
= ValueArgToConstRef(arg
);
1321 return SetCallVar(cx
, obj
, slotid
, &argcopy
);
1323 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallVar
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1324 nanojit::ACCSET_STORE_ANY
)
1328 call_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1331 JS_ASSERT(obj
->isCall());
1332 JS_ASSERT(!obj
->getProto());
1334 if (!JSID_IS_ATOM(id
))
1337 JSObject
*callee
= obj
->getCallObjCallee();
1340 JSScript
*script
= callee
->getFunctionPrivate()->script();
1341 JS_ASSERT(!script
->bindings
.hasBinding(cx
, JSID_TO_ATOM(id
)));
1346 * Resolve arguments so that we never store a particular Call object's
1347 * arguments object reference in a Call prototype's |arguments| slot.
1349 * Include JSPROP_ENUMERATE for consistency with all other Call object
1350 * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
1351 * rebinding-Call-property logic.
1353 if (callee
&& id
== ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
)) {
1354 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1355 GetCallArguments
, SetCallArguments
,
1356 JSPROP_PERMANENT
| JSPROP_SHARED
| JSPROP_ENUMERATE
,
1357 0, 0, NULL
, JSDNP_DONT_PURGE
)) {
1364 /* Control flow reaches here only if id was not resolved. */
1369 call_trace(JSTracer
*trc
, JSObject
*obj
)
1371 JS_ASSERT(obj
->isCall());
1372 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame()) {
1374 * FIXME: Hide copies of stack values rooted by fp from the Cycle
1375 * Collector, which currently lacks a non-stub Unlink implementation
1376 * for JS objects (including Call objects), so is unable to collect
1377 * cycles involving Call objects whose frames are active without this
1380 uintN first
= JSObject::CALL_RESERVED_SLOTS
;
1381 uintN count
= fp
->script()->bindings
.countArgsAndVars();
1383 JS_ASSERT(obj
->numSlots() >= first
+ count
);
1384 SetValueRangeToUndefined(obj
->getSlots() + first
, count
);
1387 MaybeMarkGenerator(trc
, obj
);
1390 JS_PUBLIC_DATA(Class
) js_CallClass
= {
1392 JSCLASS_HAS_PRIVATE
|
1393 JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS
) |
1394 JSCLASS_NEW_RESOLVE
| JSCLASS_IS_ANONYMOUS
| JSCLASS_MARK_IS_TRACE
,
1395 PropertyStub
, /* addProperty */
1396 PropertyStub
, /* delProperty */
1397 PropertyStub
, /* getProperty */
1398 PropertyStub
, /* setProperty */
1400 (JSResolveOp
)call_resolve
,
1401 NULL
, /* convert: Leave it NULL so we notice if calls ever escape */
1402 NULL
, /* finalize */
1403 NULL
, /* reserved0 */
1404 NULL
, /* checkAccess */
1406 NULL
, /* construct */
1407 NULL
, /* xdrObject */
1408 NULL
, /* hasInstance */
1409 JS_CLASS_TRACE(call_trace
)
1413 JSStackFrame::getValidCalleeObject(JSContext
*cx
, Value
*vp
)
1415 if (!isFunctionFrame()) {
1420 JSFunction
*fun
= this->fun();
1423 * See the equivalent condition in ArgGetter for the 'callee' id case, but
1424 * note that here we do not want to throw, since this escape can happen via
1425 * a foo.caller reference alone, without any debugger or indirect eval. And
1426 * alas, it seems foo.caller is still used on the Web.
1428 if (fun
->needsWrapper()) {
1429 JSObject
*wrapper
= WrapEscapingClosure(cx
, this, fun
);
1432 vp
->setObject(*wrapper
);
1436 JSObject
&funobj
= callee();
1437 vp
->setObject(funobj
);
1440 * Check for an escape attempt by a joined function object, which must go
1441 * through the frame's |this| object's method read barrier for the method
1442 * atom by which it was uniquely associated with a property.
1444 const Value
&thisv
= functionThis();
1445 if (thisv
.isObject()) {
1446 JS_ASSERT(funobj
.getFunctionPrivate() == fun
);
1448 if (&fun
->compiledFunObj() == &funobj
&& fun
->methodAtom()) {
1449 JSObject
*thisp
= &thisv
.toObject();
1450 JSObject
*first_barriered_thisp
= NULL
;
1454 * While a non-native object is responsible for handling its
1455 * entire prototype chain, notable non-natives including dense
1456 * and typed arrays have native prototypes, so keep going.
1458 if (!thisp
->isNative())
1461 if (thisp
->hasMethodBarrier()) {
1462 const Shape
*shape
= thisp
->nativeLookup(ATOM_TO_JSID(fun
->methodAtom()));
1465 * Two cases follow: the method barrier was not crossed
1466 * yet, so we cross it here; the method barrier *was*
1467 * crossed but after the call, in which case we fetch
1468 * and validate the cloned (unjoined) funobj from the
1469 * method property's slot.
1471 * In either case we must allow for the method property
1472 * to have been replaced, or its value overwritten.
1474 if (shape
->isMethod() && &shape
->methodObject() == &funobj
) {
1475 if (!thisp
->methodReadBarrier(cx
, *shape
, vp
))
1477 calleeValue().setObject(vp
->toObject());
1481 if (shape
->hasSlot()) {
1482 Value v
= thisp
->getSlot(shape
->slot
);
1485 if (IsFunctionObject(v
, &clone
) &&
1486 GET_FUNCTION_PRIVATE(cx
, clone
) == fun
&&
1487 clone
->hasMethodObj(*thisp
)) {
1488 JS_ASSERT(clone
!= &funobj
);
1490 calleeValue().setObject(*clone
);
1496 if (!first_barriered_thisp
)
1497 first_barriered_thisp
= thisp
;
1499 } while ((thisp
= thisp
->getProto()) != NULL
);
1501 if (!first_barriered_thisp
)
1505 * At this point, we couldn't find an already-existing clone (or
1506 * force to exist a fresh clone) created via thisp's method read
1507 * barrier, so we must clone fun and store it in fp's callee to
1508 * avoid re-cloning upon repeated foo.caller access.
1510 * This must mean the code in js_DeleteProperty could not find this
1511 * stack frame on the stack when the method was deleted. We've lost
1512 * track of the method, so we associate it with the first barriered
1513 * object found starting from thisp on the prototype chain.
1515 JSObject
*newfunobj
= CloneFunctionObject(cx
, fun
, fun
->getParent());
1518 newfunobj
->setMethodObj(*first_barriered_thisp
);
1519 calleeValue().setObject(*newfunobj
);
1520 vp
->setObject(*newfunobj
);
1528 /* Generic function tinyids. */
1530 FUN_ARGUMENTS
= -1, /* predefined arguments local variable */
1531 FUN_LENGTH
= -2, /* number of actual args, arity if inactive */
1532 FUN_ARITY
= -3, /* number of formal parameters; desired argc */
1533 FUN_NAME
= -4, /* function name, "" if anonymous */
1534 FUN_CALLER
= -5 /* Function.prototype.caller, backward compat */
1538 fun_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1540 if (!JSID_IS_INT(id
))
1543 jsint slot
= JSID_TO_INT(id
);
1546 * Loop because getter and setter can be delegated from another class,
1547 * but loop only for FUN_LENGTH because we must pretend that f.length
1548 * is in each function instance f, per ECMA-262, instead of only in the
1549 * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1550 * to make it appear so).
1552 * This code couples tightly to the attributes for lazyFunctionDataProps[]
1553 * and poisonPillProps[] initializers below, and to js_SetProperty and
1554 * js_HasOwnProperty.
1556 * It's important to allow delegating objects, even though they inherit
1557 * this getter (fun_getProperty), to override arguments, arity, caller,
1558 * and name. If we didn't return early for slot != FUN_LENGTH, we would
1559 * clobber *vp with the native property value, instead of letting script
1560 * override that value in delegating objects.
1562 * Note how that clobbering is what simulates JSPROP_READONLY for all of
1563 * the non-standard properties when the directly addressed object (obj)
1564 * is a function object (i.e., when this loop does not iterate).
1567 while (!(fun
= (JSFunction
*)
1568 GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
))) {
1569 if (slot
!= FUN_LENGTH
)
1571 obj
= obj
->getProto();
1576 /* Find fun's top-most activation record. */
1578 for (fp
= js_GetTopStackFrame(cx
);
1579 fp
&& (fp
->maybeFun() != fun
|| fp
->isEvalOrDebuggerFrame());
1586 /* Warn if strict about f.arguments or equivalent unqualified uses. */
1587 if (!JS_ReportErrorFlagsAndNumber(cx
,
1588 JSREPORT_WARNING
| JSREPORT_STRICT
,
1589 js_GetErrorMessage
, NULL
,
1590 JSMSG_DEPRECATED_USAGE
,
1591 js_arguments_str
)) {
1595 if (!js_GetArgsValue(cx
, fp
, vp
))
1604 vp
->setInt32(fun
->nargs
);
1608 vp
->setString(fun
->atom
? ATOM_TO_STRING(fun
->atom
)
1609 : cx
->runtime
->emptyString
);
1614 if (fp
&& fp
->prev() && !fp
->prev()->getValidCalleeObject(cx
, vp
))
1617 if (vp
->isObject()) {
1618 JSObject
&caller
= vp
->toObject();
1620 /* Censor the caller if it is from another compartment. */
1621 if (caller
.getCompartment() != cx
->compartment
) {
1623 } else if (caller
.isFunction()) {
1624 JSFunction
*callerFun
= caller
.getFunctionPrivate();
1625 if (callerFun
->isInterpreted() && callerFun
->inStrictMode()) {
1626 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
1627 JSMSG_CALLER_IS_STRICT
);
1635 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1636 if (fp
&& fp
->isFunctionFrame() && uint16(slot
) < fp
->numFormalArgs())
1637 *vp
= fp
->formalArg(slot
);
1644 struct LazyFunctionDataProp
{
1650 struct PoisonPillProp
{
1655 /* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
1657 static const LazyFunctionDataProp lazyFunctionDataProps
[] = {
1658 {ATOM_OFFSET(arity
), FUN_ARITY
, JSPROP_PERMANENT
|JSPROP_READONLY
},
1659 {ATOM_OFFSET(name
), FUN_NAME
, JSPROP_PERMANENT
|JSPROP_READONLY
},
1662 /* Properties censored into [[ThrowTypeError]] in strict mode. */
1663 static const PoisonPillProp poisonPillProps
[] = {
1664 {ATOM_OFFSET(arguments
), FUN_ARGUMENTS
},
1665 {ATOM_OFFSET(caller
), FUN_CALLER
},
1669 fun_enumerate(JSContext
*cx
, JSObject
*obj
)
1671 JS_ASSERT(obj
->isFunction());
1676 if (!obj
->isBoundFunction()) {
1677 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1678 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1682 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
);
1683 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1686 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1687 const LazyFunctionDataProp
&lfp
= lazyFunctionDataProps
[i
];
1688 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, lfp
.atomOffset
));
1689 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1693 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(poisonPillProps
); i
++) {
1694 const PoisonPillProp
&p
= poisonPillProps
[i
];
1695 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
));
1696 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1704 fun_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1707 if (!JSID_IS_ATOM(id
))
1710 JSFunction
*fun
= obj
->getFunctionPrivate();
1712 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.classPrototypeAtom
)) {
1714 * Native or "built-in" functions do not have a .prototype property per
1715 * ECMA-262 (all editions). Built-in constructor functions, e.g. Object
1716 * and Function to name two conspicuous examples, do have a .prototype
1717 * property, but it is created eagerly by js_InitClass (jsobj.cpp).
1719 * ES5 15.3.4: the non-native function object named Function.prototype
1720 * must not have a .prototype property.
1722 * ES5 15.3.4.5: bound functions don't have a prototype property. The
1723 * isNative() test covers this case because bound functions are native
1724 * functions by definition/construction.
1726 if (fun
->isNative() || fun
->isFunctionPrototype())
1730 * Assert that fun is not a compiler-created function object, which
1731 * must never leak to script or embedding code and then be mutated.
1732 * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
1734 JS_ASSERT(!IsInternalFunctionObject(obj
));
1735 JS_ASSERT(!obj
->isBoundFunction());
1738 * Make the prototype object an instance of Object with the same parent
1739 * as the function object itself.
1741 JSObject
*parent
= obj
->getParent();
1743 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
1745 proto
= NewNativeClassInstance(cx
, &js_ObjectClass
, proto
, parent
);
1750 * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1751 * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1752 * native "system" constructors such as Object or Function. So lazily
1753 * set the former here in fun_resolve, but eagerly define the latter
1754 * in js_InitClass, with the right attributes.
1756 if (!js_SetClassPrototype(cx
, obj
, proto
, JSPROP_PERMANENT
))
1763 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
1764 JS_ASSERT(!IsInternalFunctionObject(obj
));
1765 if (!js_DefineNativeProperty(cx
, obj
, id
, Int32Value(fun
->nargs
),
1766 PropertyStub
, PropertyStub
,
1767 JSPROP_PERMANENT
| JSPROP_READONLY
, 0, 0, NULL
)) {
1774 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1775 const LazyFunctionDataProp
*lfp
= &lazyFunctionDataProps
[i
];
1777 if (JSID_IS_ATOM(id
, OFFSET_TO_ATOM(cx
->runtime
, lfp
->atomOffset
))) {
1778 JS_ASSERT(!IsInternalFunctionObject(obj
));
1780 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1781 fun_getProperty
, PropertyStub
,
1782 lfp
->attrs
, Shape::HAS_SHORTID
,
1783 lfp
->tinyid
, NULL
)) {
1791 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(poisonPillProps
); i
++) {
1792 const PoisonPillProp
&p
= poisonPillProps
[i
];
1794 if (JSID_IS_ATOM(id
, OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
))) {
1795 JS_ASSERT(!IsInternalFunctionObject(obj
));
1797 PropertyOp getter
, setter
;
1798 uintN attrs
= JSPROP_PERMANENT
;
1799 if (fun
->isInterpreted() ? fun
->inStrictMode() : obj
->isBoundFunction()) {
1800 JSObject
*throwTypeError
= obj
->getThrowTypeError();
1802 getter
= CastAsPropertyOp(throwTypeError
);
1803 setter
= CastAsPropertyOp(throwTypeError
);
1804 attrs
|= JSPROP_GETTER
| JSPROP_SETTER
;
1806 getter
= fun_getProperty
;
1807 setter
= PropertyStub
;
1810 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1812 attrs
, Shape::HAS_SHORTID
,
1826 /* XXX store parent and proto, if defined */
1828 js_XDRFunctionObject(JSXDRState
*xdr
, JSObject
**objp
)
1832 uint32 firstword
; /* flag telling whether fun->atom is non-null,
1833 plus for fun->u.i.skipmin, fun->u.i.wrapper,
1834 and 14 bits reserved for future use */
1835 uint32 flagsword
; /* word for argument count and fun->flags */
1838 if (xdr
->mode
== JSXDR_ENCODE
) {
1839 fun
= GET_FUNCTION_PRIVATE(cx
, *objp
);
1840 if (!FUN_INTERPRETED(fun
)) {
1841 JSAutoByteString funNameBytes
;
1842 if (const char *name
= GetFunctionNameBytes(cx
, fun
, &funNameBytes
)) {
1843 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NOT_SCRIPTED_FUNCTION
,
1848 if (fun
->u
.i
.wrapper
) {
1849 JSAutoByteString funNameBytes
;
1850 if (const char *name
= GetFunctionNameBytes(cx
, fun
, &funNameBytes
))
1851 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_XDR_CLOSURE_WRAPPER
, name
);
1854 JS_ASSERT((fun
->u
.i
.wrapper
& ~1U) == 0);
1855 firstword
= (fun
->u
.i
.skipmin
<< 2) | (fun
->u
.i
.wrapper
<< 1) | !!fun
->atom
;
1856 flagsword
= (fun
->nargs
<< 16) | fun
->flags
;
1858 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, JSFUN_INTERPRETED
, NULL
, NULL
);
1861 FUN_OBJECT(fun
)->clearParent();
1862 FUN_OBJECT(fun
)->clearProto();
1865 AutoObjectRooter
tvr(cx
, FUN_OBJECT(fun
));
1867 if (!JS_XDRUint32(xdr
, &firstword
))
1869 if ((firstword
& 1U) && !js_XDRAtom(xdr
, &fun
->atom
))
1871 if (!JS_XDRUint32(xdr
, &flagsword
))
1874 if (xdr
->mode
== JSXDR_DECODE
) {
1875 fun
->nargs
= flagsword
>> 16;
1876 JS_ASSERT((flagsword
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
);
1877 fun
->flags
= uint16(flagsword
);
1878 fun
->u
.i
.skipmin
= uint16(firstword
>> 2);
1879 fun
->u
.i
.wrapper
= JSPackedBool((firstword
>> 1) & 1);
1882 if (!js_XDRScript(xdr
, &fun
->u
.i
.script
, NULL
))
1885 if (xdr
->mode
== JSXDR_DECODE
) {
1886 *objp
= FUN_OBJECT(fun
);
1887 #ifdef CHECK_SCRIPT_OWNER
1888 fun
->script()->owner
= NULL
;
1890 JS_ASSERT(fun
->nargs
== fun
->script()->bindings
.countArgs());
1891 js_CallNewScriptHook(cx
, fun
->script(), fun
);
1897 #else /* !JS_HAS_XDR */
1899 #define js_XDRFunctionObject NULL
1901 #endif /* !JS_HAS_XDR */
1904 * [[HasInstance]] internal method for Function objects: fetch the .prototype
1905 * property of its 'this' parameter, and walks the prototype chain of v (only
1906 * if v is an object) returning true if .prototype is found.
1909 fun_hasInstance(JSContext
*cx
, JSObject
*obj
, const Value
*v
, JSBool
*bp
)
1911 while (obj
->isFunction()) {
1912 if (!obj
->isBoundFunction())
1914 obj
= obj
->getBoundFunctionTarget();
1917 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1919 if (!obj
->getProperty(cx
, id
, &pval
))
1922 if (pval
.isPrimitive()) {
1924 * Throw a runtime error if instanceof is called on a function that
1925 * has a non-object as its .prototype value.
1927 js_ReportValueError(cx
, JSMSG_BAD_PROTOTYPE
, -1, ObjectValue(*obj
), NULL
);
1931 *bp
= js_IsDelegate(cx
, &pval
.toObject(), *v
);
1936 fun_trace(JSTracer
*trc
, JSObject
*obj
)
1938 /* A newborn function object may have a not yet initialized private slot. */
1939 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
1944 /* obj is a cloned function object, trace the clone-parent, fun. */
1945 MarkObject(trc
, *fun
, "private");
1947 /* The function could be a flat closure with upvar copies in the clone. */
1948 if (fun
->isFlatClosure() && fun
->script()->bindings
.hasUpvars()) {
1949 MarkValueRange(trc
, fun
->script()->bindings
.countUpvars(),
1950 obj
->getFlatClosureUpvars(), "upvars");
1956 MarkString(trc
, ATOM_TO_STRING(fun
->atom
), "atom");
1958 if (fun
->isInterpreted() && fun
->script())
1959 js_TraceScript(trc
, fun
->script());
1963 fun_finalize(JSContext
*cx
, JSObject
*obj
)
1965 /* Ignore newborn function objects. */
1966 JSFunction
*fun
= obj
->getFunctionPrivate();
1970 /* Cloned function objects may be flat closures with upvars to free. */
1972 if (fun
->isFlatClosure() && fun
->script()->bindings
.hasUpvars())
1973 cx
->free((void *) obj
->getFlatClosureUpvars());
1978 * Null-check fun->script() because the parser sets interpreted very early.
1980 if (fun
->isInterpreted() && fun
->script())
1981 js_DestroyScriptFromGC(cx
, fun
->script());
1985 * Reserve two slots in all function objects for XPConnect. Note that this
1986 * does not bloat every instance, only those on which reserved slots are set,
1987 * and those on which ad-hoc properties are defined.
1989 JS_PUBLIC_DATA(Class
) js_FunctionClass
= {
1991 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
1992 JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS
) |
1993 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Function
),
1994 PropertyStub
, /* addProperty */
1995 PropertyStub
, /* delProperty */
1996 PropertyStub
, /* getProperty */
1997 PropertyStub
, /* setProperty */
1999 (JSResolveOp
)fun_resolve
,
2002 NULL
, /* reserved0 */
2003 NULL
, /* checkAccess */
2005 NULL
, /* construct */
2006 js_XDRFunctionObject
,
2008 JS_CLASS_TRACE(fun_trace
)
2012 fun_toStringHelper(JSContext
*cx
, JSObject
*obj
, uintN indent
)
2014 if (!obj
->isFunction()) {
2015 if (obj
->isFunctionProxy())
2016 return JSProxy::fun_toString(cx
, obj
, indent
);
2017 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2018 JSMSG_INCOMPATIBLE_PROTO
,
2019 js_Function_str
, js_toString_str
,
2024 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
2027 return JS_DecompileFunction(cx
, fun
, indent
);
2031 fun_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
2033 JS_ASSERT(IsFunctionObject(vp
[0]));
2034 uint32_t indent
= 0;
2036 if (argc
!= 0 && !ValueToECMAUint32(cx
, vp
[2], &indent
))
2039 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2043 JSString
*str
= fun_toStringHelper(cx
, obj
, indent
);
2053 fun_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
2055 JS_ASSERT(IsFunctionObject(vp
[0]));
2057 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2061 JSString
*str
= fun_toStringHelper(cx
, obj
, JS_DONT_PRETTY_PRINT
);
2071 js_fun_call(JSContext
*cx
, uintN argc
, Value
*vp
)
2075 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2080 if (!js_IsCallable(fval
)) {
2081 JSString
*str
= js_ValueToString(cx
, fval
);
2083 JSAutoByteString
bytes(cx
, str
);
2085 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2086 JSMSG_INCOMPATIBLE_PROTO
,
2087 js_Function_str
, js_call_str
,
2094 Value
*argv
= vp
+ 2;
2097 thisv
.setUndefined();
2105 /* Allocate stack space for fval, obj, and the args. */
2106 InvokeArgsGuard args
;
2107 if (!cx
->stack().pushInvokeArgs(cx
, argc
, &args
))
2110 /* Push fval, thisv, and the args. */
2111 args
.callee() = fval
;
2112 args
.thisv() = thisv
;
2113 memcpy(args
.argv(), argv
, argc
* sizeof *argv
);
2115 bool ok
= Invoke(cx
, args
, 0);
2122 js_fun_apply(JSContext
*cx
, uintN argc
, Value
*vp
)
2124 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2130 if (!js_IsCallable(fval
)) {
2131 if (JSString
*str
= js_ValueToString(cx
, fval
)) {
2132 JSAutoByteString
bytes(cx
, str
);
2134 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2135 JSMSG_INCOMPATIBLE_PROTO
,
2136 js_Function_str
, js_apply_str
,
2144 if (argc
< 2 || vp
[3].isNullOrUndefined())
2145 return js_fun_call(cx
, (argc
> 0) ? 1 : 0, vp
);
2147 /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
2150 if (!vp
[3].isObject()) {
2151 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_APPLY_ARGS
, js_apply_str
);
2156 * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
2157 * original version of ES5).
2159 JSObject
*aobj
= &vp
[3].toObject();
2161 if (!js_GetLengthProperty(cx
, aobj
, &length
))
2167 uintN n
= uintN(JS_MIN(length
, JS_ARGS_LENGTH_MAX
));
2169 InvokeArgsGuard args
;
2170 if (!cx
->stack().pushInvokeArgs(cx
, n
, &args
))
2173 /* Push fval, obj, and aobj's elements as args. */
2174 args
.callee() = fval
;
2175 args
.thisv() = vp
[2];
2178 if (!GetElements(cx
, aobj
, n
, args
.argv()))
2182 if (!Invoke(cx
, args
, 0))
2189 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
);
2192 JSObject::initBoundFunction(JSContext
*cx
, const Value
&thisArg
,
2193 const Value
*args
, uintN argslen
)
2195 JS_ASSERT(isFunction());
2197 flags
|= JSObject::BOUND_FUNCTION
;
2198 getSlotRef(JSSLOT_BOUND_FUNCTION_THIS
) = thisArg
;
2199 getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT
).setPrivateUint32(argslen
);
2201 /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
2202 EmptyShape
*empty
= EmptyShape::create(cx
, clasp
);
2206 empty
->slotSpan
+= argslen
;
2209 if (!ensureInstanceReservedSlots(cx
, argslen
))
2212 JS_ASSERT(numSlots() >= argslen
+ FUN_CLASS_RESERVED_SLOTS
);
2213 memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS
, args
, argslen
* sizeof(Value
));
2219 JSObject::getBoundFunctionTarget() const
2221 JS_ASSERT(isFunction());
2222 JS_ASSERT(isBoundFunction());
2224 /* Bound functions abuse |parent| to store their target function. */
2228 inline const js::Value
&
2229 JSObject::getBoundFunctionThis() const
2231 JS_ASSERT(isFunction());
2232 JS_ASSERT(isBoundFunction());
2234 return getSlot(JSSLOT_BOUND_FUNCTION_THIS
);
2237 inline const js::Value
*
2238 JSObject::getBoundFunctionArguments(uintN
&argslen
) const
2240 JS_ASSERT(isFunction());
2241 JS_ASSERT(isBoundFunction());
2243 argslen
= getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT
).toPrivateUint32();
2244 JS_ASSERT_IF(argslen
> 0, numSlots() >= argslen
);
2246 return getSlots() + FUN_CLASS_RESERVED_SLOTS
;
2249 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
2251 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
)
2253 JSObject
*obj
= &vp
[0].toObject();
2254 JS_ASSERT(obj
->isFunction());
2255 JS_ASSERT(obj
->isBoundFunction());
2259 bool constructing
= IsConstructing(vp
);
2261 /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
2263 const Value
*boundArgs
= obj
->getBoundFunctionArguments(argslen
);
2265 if (argc
+ argslen
> JS_ARGS_LENGTH_MAX
) {
2266 js_ReportAllocationOverflow(cx
);
2270 /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
2271 JSObject
*target
= obj
->getBoundFunctionTarget();
2273 /* 15.3.4.5.1 step 2. */
2274 const Value
&boundThis
= obj
->getBoundFunctionThis();
2276 InvokeArgsGuard args
;
2277 if (!cx
->stack().pushInvokeArgs(cx
, argc
+ argslen
, &args
))
2280 /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
2281 memcpy(args
.argv(), boundArgs
, argslen
* sizeof(Value
));
2282 memcpy(args
.argv() + argslen
, vp
+ 2, argc
* sizeof(Value
));
2284 /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
2285 args
.callee().setObject(*target
);
2288 args
.thisv() = boundThis
;
2290 if (constructing
? !InvokeConstructor(cx
, args
) : !Invoke(cx
, args
, 0))
2299 fun_bind(JSContext
*cx
, uintN argc
, Value
*vp
)
2302 JSObject
*target
= ComputeThisFromVp(cx
, vp
);
2307 if (!target
->isCallable()) {
2308 if (JSString
*str
= js_ValueToString(cx
, vp
[1])) {
2309 JSAutoByteString
bytes(cx
, str
);
2311 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2312 JSMSG_INCOMPATIBLE_PROTO
,
2313 js_Function_str
, "bind", bytes
.ptr());
2329 if (target
->isFunction()) {
2330 uintN nargs
= target
->getFunctionPrivate()->nargs
;
2331 if (nargs
> argslen
)
2332 length
= nargs
- argslen
;
2335 /* Step 4-6, 10-11. */
2336 JSAtom
*name
= target
->isFunction() ? target
->getFunctionPrivate()->atom
: NULL
;
2338 /* NB: Bound functions abuse |parent| to store their target. */
2340 js_NewFunction(cx
, NULL
, CallOrConstructBoundFunction
, length
,
2341 JSFUN_CONSTRUCTOR
, target
, name
);
2346 Value thisArg
= argc
>= 1 ? vp
[2] : UndefinedValue();
2347 if (!funobj
->initBoundFunction(cx
, thisArg
, args
, argslen
))
2350 /* Steps 17, 19-21 are handled by fun_resolve. */
2351 /* Step 18 is the default for new functions. */
2354 vp
->setObject(*funobj
);
2358 static JSFunctionSpec function_methods
[] = {
2360 JS_FN(js_toSource_str
, fun_toSource
, 0,0),
2362 JS_FN(js_toString_str
, fun_toString
, 0,0),
2363 JS_FN(js_apply_str
, js_fun_apply
, 2,0),
2364 JS_FN(js_call_str
, js_fun_call
, 1,0),
2365 JS_FN("bind", fun_bind
, 1,0),
2370 Function(JSContext
*cx
, uintN argc
, Value
*vp
)
2372 JSObject
*obj
= NewFunction(cx
, NULL
);
2376 /* N.B. overwriting callee with return value */
2377 JSObject
*parent
= vp
[0].toObject().getParent();
2378 vp
[0].setObject(*obj
);
2381 * NB: (new Function) is not lexically closed by its caller, it's just an
2382 * anonymous function in the top-level scope that its constructor inhabits.
2383 * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2384 * and so would a call to f from another top-level's script or function.
2386 * In older versions, before call objects, a new Function was adopted by
2387 * its running context's globalObject, which might be different from the
2388 * top-level reachable from scopeChain (in HTML frames, e.g.).
2390 JSFunction
*fun
= js_NewFunction(cx
, obj
, NULL
, 0, JSFUN_LAMBDA
| JSFUN_INTERPRETED
,
2391 parent
, cx
->runtime
->atomState
.anonymousAtom
);
2396 * Function is static and not called directly by other functions in this
2397 * file, therefore it is callable only as a native function by js_Invoke.
2398 * Find the scripted caller, possibly skipping other native frames such as
2399 * are built for Function.prototype.call or .apply activations that invoke
2400 * Function indirectly from a script.
2402 JSStackFrame
*caller
= js_GetScriptedCaller(cx
, NULL
);
2404 const char *filename
;
2405 JSPrincipals
*principals
;
2407 JSObject
*callee
= &JS_CALLEE(cx
, vp
).toObject();
2408 principals
= js_EvalFramePrincipals(cx
, callee
, caller
);
2409 filename
= js_ComputeFilename(cx
, caller
, principals
, &lineno
);
2416 /* Belt-and-braces: check that the caller has access to parent. */
2417 if (!js_CheckPrincipalsAccess(cx
, parent
, principals
,
2418 CLASS_ATOM(cx
, Function
))) {
2423 * CSP check: whether new Function() is allowed at all.
2424 * Report errors via CSP is done in the script security manager.
2425 * js_CheckContentSecurityPolicy is defined in jsobj.cpp
2427 if (!js_CheckContentSecurityPolicy(cx
, parent
)) {
2428 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CSP_BLOCKED_FUNCTION
);
2432 Bindings
bindings(cx
);
2433 AutoBindingsRooter
root(cx
, bindings
);
2435 Value
*argv
= vp
+ 2;
2436 uintN n
= argc
? argc
- 1 : 0;
2438 enum { OK
, BAD
, BAD_FORMAL
} state
;
2441 * Collect the function-argument arguments into one string, separated
2442 * by commas, then make a tokenstream from that string, and scan it to
2443 * get the arguments. We need to throw the full scanner at the
2444 * problem, because the argument string can legitimately contain
2445 * comments and linefeeds. XXX It might be better to concatenate
2446 * everything up into a function definition and pass it to the
2447 * compiler, but doing it this way is less of a delta from the old
2448 * code. See ECMA 15.3.2.1.
2451 size_t args_length
= 0;
2452 for (uintN i
= 0; i
< n
; i
++) {
2453 /* Collect the lengths for all the function-argument arguments. */
2454 JSString
*arg
= js_ValueToString(cx
, argv
[i
]);
2457 argv
[i
].setString(arg
);
2460 * Check for overflow. The < test works because the maximum
2461 * JSString length fits in 2 fewer bits than size_t has.
2463 size_t old_args_length
= args_length
;
2464 args_length
= old_args_length
+ arg
->length();
2465 if (args_length
< old_args_length
) {
2466 js_ReportAllocationOverflow(cx
);
2471 /* Add 1 for each joining comma and check for overflow (two ways). */
2472 size_t old_args_length
= args_length
;
2473 args_length
= old_args_length
+ n
- 1;
2474 if (args_length
< old_args_length
||
2475 args_length
>= ~(size_t)0 / sizeof(jschar
)) {
2476 js_ReportAllocationOverflow(cx
);
2481 * Allocate a string to hold the concatenated arguments, including room
2482 * for a terminating 0. Mark cx->tempPool for later release, to free
2483 * collected_args and its tokenstream in one swoop.
2485 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2487 JS_ARENA_ALLOCATE_CAST(cp
, jschar
*, &cx
->tempPool
,
2488 (args_length
+1) * sizeof(jschar
));
2490 js_ReportOutOfScriptQuota(cx
);
2493 jschar
*collected_args
= cp
;
2496 * Concatenate the arguments into the new string, separated by commas.
2498 for (uintN i
= 0; i
< n
; i
++) {
2499 JSString
*arg
= argv
[i
].toString();
2500 size_t arg_length
= arg
->length();
2501 const jschar
*arg_chars
= arg
->getChars(cx
);
2503 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2506 (void) js_strncpy(cp
, arg_chars
, arg_length
);
2509 /* Add separating comma or terminating 0. */
2510 *cp
++ = (i
+ 1 < n
) ? ',' : 0;
2513 /* Initialize a tokenstream that reads from the given string. */
2515 if (!ts
.init(cx
->findVersion(), collected_args
, args_length
, filename
, lineno
)) {
2516 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2520 /* The argument string may be empty or contain no tokens. */
2521 TokenKind tt
= ts
.getToken();
2522 if (tt
!= TOK_EOF
) {
2525 * Check that it's a name. This also implicitly guards against
2526 * TOK_ERROR, which was already reported.
2532 * Get the atom corresponding to the name from the token
2533 * stream; we're assured at this point that it's a valid
2536 JSAtom
*atom
= ts
.currentToken().t_atom
;
2538 /* Check for a duplicate parameter name. */
2539 if (bindings
.hasBinding(cx
, atom
)) {
2540 JSAutoByteString name
;
2541 if (!js_AtomToPrintableString(cx
, atom
, &name
)) {
2545 if (!ReportCompileErrorNumber(cx
, &ts
, NULL
,
2546 JSREPORT_WARNING
| JSREPORT_STRICT
,
2547 JSMSG_DUPLICATE_FORMAL
, name
.ptr())) {
2554 if (!bindings
.addArgument(cx
, atom
, &dummy
)) {
2560 * Get the next token. Stop on end of stream. Otherwise
2561 * insist on a comma, get another name, and iterate.
2566 if (tt
!= TOK_COMMA
)
2574 if (state
== BAD_FORMAL
&& !ts
.isError()) {
2576 * Report "malformed formal parameter" iff no illegal char or
2577 * similar scanner error was already reported.
2579 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2583 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2590 str
= js_ValueToString(cx
, argv
[argc
- 1]);
2593 argv
[argc
- 1].setString(str
);
2595 str
= cx
->runtime
->emptyString
;
2598 size_t length
= str
->length();
2599 const jschar
*chars
= str
->getChars(cx
);
2603 return Compiler::compileFunctionBody(cx
, fun
, principals
, &bindings
,
2604 chars
, length
, filename
, lineno
);
2608 ThrowTypeError(JSContext
*cx
, uintN argc
, Value
*vp
)
2610 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
2611 JSMSG_THROW_TYPE_ERROR
);
2616 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
)
2618 JSObject
*proto
= js_InitClass(cx
, obj
, NULL
, &js_FunctionClass
, Function
, 1,
2619 NULL
, function_methods
, NULL
, NULL
);
2623 JSFunction
*fun
= js_NewFunction(cx
, proto
, NULL
, 0, JSFUN_INTERPRETED
, obj
, NULL
);
2626 fun
->flags
|= JSFUN_PROTOTYPE
;
2628 JSScript
*script
= JSScript::NewScript(cx
, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2631 script
->setVersion(JSVERSION_DEFAULT
);
2632 script
->noScriptRval
= true;
2633 script
->code
[0] = JSOP_STOP
;
2634 script
->code
[1] = SRC_NULL
;
2635 #ifdef CHECK_SCRIPT_OWNER
2636 script
->owner
= NULL
;
2638 fun
->u
.i
.script
= script
;
2640 if (obj
->isGlobal()) {
2641 /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
2642 JSObject
*throwTypeError
=
2643 js_NewFunction(cx
, NULL
, reinterpret_cast<Native
>(ThrowTypeError
), 0,
2645 if (!throwTypeError
)
2648 JS_ALWAYS_TRUE(js_SetReservedSlot(cx
, obj
, JSRESERVED_GLOBAL_THROWTYPEERROR
,
2649 ObjectValue(*throwTypeError
)));
2656 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, Native native
, uintN nargs
,
2657 uintN flags
, JSObject
*parent
, JSAtom
*atom
)
2662 JS_ASSERT(funobj
->isFunction());
2663 funobj
->setParent(parent
);
2665 funobj
= NewFunction(cx
, parent
);
2669 JS_ASSERT(!funobj
->getPrivate());
2670 fun
= (JSFunction
*) funobj
;
2672 /* Initialize all function members. */
2673 fun
->nargs
= uint16(nargs
);
2674 fun
->flags
= flags
& (JSFUN_FLAGS_MASK
| JSFUN_KINDMASK
| JSFUN_TRCINFO
);
2675 if ((flags
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
) {
2677 JS_ASSERT(nargs
== 0);
2678 fun
->u
.i
.skipmin
= 0;
2679 fun
->u
.i
.wrapper
= false;
2680 fun
->u
.i
.script
= NULL
;
2682 fun
->u
.n
.clasp
= NULL
;
2683 if (flags
& JSFUN_TRCINFO
) {
2685 JSNativeTraceInfo
*trcinfo
=
2686 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo
*, native
);
2687 fun
->u
.n
.native
= (js::Native
) trcinfo
->native
;
2688 fun
->u
.n
.trcinfo
= trcinfo
;
2690 fun
->u
.n
.trcinfo
= NULL
;
2693 fun
->u
.n
.native
= native
;
2694 fun
->u
.n
.trcinfo
= NULL
;
2696 JS_ASSERT(fun
->u
.n
.native
);
2700 /* Set private to self to indicate non-cloned fully initialized function. */
2701 FUN_OBJECT(fun
)->setPrivate(fun
);
2705 JSObject
* JS_FASTCALL
2706 js_CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
,
2713 if (cx
->compartment
== fun
->compartment()) {
2715 * The cloned function object does not need the extra JSFunction members
2716 * beyond JSObject as it points to fun via the private slot.
2718 clone
= NewNativeClassInstance(cx
, &js_FunctionClass
, proto
, parent
);
2721 clone
->setPrivate(fun
);
2724 * Across compartments we have to deep copy JSFunction and clone the
2725 * script (for interpreted functions).
2727 clone
= NewFunction(cx
, parent
);
2730 JSFunction
*cfun
= (JSFunction
*) clone
;
2731 cfun
->nargs
= fun
->nargs
;
2732 cfun
->flags
= fun
->flags
;
2733 cfun
->u
= fun
->getFunctionPrivate()->u
;
2734 cfun
->atom
= fun
->atom
;
2735 clone
->setPrivate(cfun
);
2736 if (cfun
->isInterpreted()) {
2737 JSScript
*script
= cfun
->u
.i
.script
;
2739 JS_ASSERT(script
->compartment
== fun
->compartment());
2740 JS_ASSERT(script
->compartment
!= cx
->compartment
);
2742 cfun
->u
.i
.script
= js_CloneScript(cx
, script
);
2743 if (!cfun
->u
.i
.script
)
2745 #ifdef CHECK_SCRIPT_OWNER
2746 cfun
->script()->owner
= NULL
;
2748 js_CallNewScriptHook(cx
, cfun
->script(), cfun
);
2755 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CloneFunctionObject
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
, 0,
2756 nanojit::ACCSET_STORE_ANY
)
2760 * Create a new flat closure, but don't initialize the imported upvar
2761 * values. The tracer calls this function and then initializes the upvar
2764 JSObject
* JS_FASTCALL
2765 js_AllocFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
)
2767 JS_ASSERT(fun
->isFlatClosure());
2768 JS_ASSERT(JSScript::isValidOffset(fun
->script()->upvarsOffset
) ==
2769 fun
->script()->bindings
.hasUpvars());
2770 JS_ASSERT_IF(JSScript::isValidOffset(fun
->script()->upvarsOffset
),
2771 fun
->script()->upvars()->length
== fun
->script()->bindings
.countUpvars());
2773 JSObject
*closure
= CloneFunctionObject(cx
, fun
, scopeChain
);
2777 uint32 nslots
= fun
->script()->bindings
.countUpvars();
2781 Value
*upvars
= (Value
*) cx
->malloc(nslots
* sizeof(Value
));
2785 closure
->setFlatClosureUpvars(upvars
);
2789 JS_DEFINE_CALLINFO_3(extern, OBJECT
, js_AllocFlatClosure
,
2790 CONTEXT
, FUNCTION
, OBJECT
, 0, nanojit::ACCSET_STORE_ANY
)
2793 js_NewFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSOp op
, size_t oplen
)
2796 * Flat closures cannot yet be partial, that is, all upvars must be copied,
2797 * or the closure won't be flattened. Therefore they do not need to search
2798 * enclosing scope objects via JSOP_NAME, etc.
2800 * FIXME: bug 545759 proposes to enable partial flat closures. Fixing this
2801 * bug requires a GetScopeChainFast call here, along with JS_REQUIRES_STACK
2802 * annotations on this function's prototype and definition.
2804 VOUCH_DOES_NOT_REQUIRE_STACK();
2805 JSObject
*scopeChain
= &cx
->fp()->scopeChain();
2807 JSObject
*closure
= js_AllocFlatClosure(cx
, fun
, scopeChain
);
2808 if (!closure
|| !fun
->script()->bindings
.hasUpvars())
2811 Value
*upvars
= closure
->getFlatClosureUpvars();
2812 uintN level
= fun
->u
.i
.script
->staticLevel
;
2813 JSUpvarArray
*uva
= fun
->script()->upvars();
2815 for (uint32 i
= 0, n
= uva
->length
; i
< n
; i
++)
2816 upvars
[i
] = GetUpvar(cx
, level
, uva
->vector
[i
]);
2822 js_NewDebuggableFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2824 JS_ASSERT(cx
->fp()->fun()->flags
& JSFUN_HEAVYWEIGHT
);
2825 JS_ASSERT(!cx
->fp()->fun()->optimizedClosure());
2826 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
2828 return WrapEscapingClosure(cx
, cx
->fp(), fun
);
2832 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, jsid id
, Native native
,
2833 uintN nargs
, uintN attrs
)
2838 if (attrs
& JSFUN_STUB_GSOPS
) {
2840 * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2841 * the defined property's attributes. This allows us to encode another,
2842 * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2845 attrs
&= ~JSFUN_STUB_GSOPS
;
2846 gsop
= PropertyStub
;
2852 * Historically, all objects have had a parent member as intrinsic scope
2853 * chain link. We want to move away from this universal parent, but JS
2854 * requires that function objects have something like parent (ES3 and ES5
2855 * call it the [[Scope]] internal property), to bake a particular static
2856 * scope environment into each function object.
2858 * All function objects thus have parent, including all native functions.
2859 * All native functions defined by the JS_DefineFunction* APIs are created
2860 * via the call below to js_NewFunction, which passes obj as the parent
2861 * parameter, and so binds fun's parent to obj using JSObject::setParent,
2862 * under js_NewFunction (in JSObject::init, called from NewObject -- see
2865 * But JSObject::setParent sets the DELEGATE object flag on its receiver,
2866 * to mark the object as a proto or parent of another object. Such objects
2867 * may intervene in property lookups and scope chain searches, so require
2868 * special handling when caching lookup and search results (since such
2869 * intervening objects can in general grow shadowing properties later).
2871 * Thus using setParent prematurely flags certain objects, notably class
2872 * prototypes, so that defining native methods on them, where the method's
2873 * name (e.g., toString) is already bound on Object.prototype, triggers
2874 * shadowingShapeChange events and gratuitous shape regeneration.
2876 * To fix this longstanding bug, we set check whether obj is already a
2877 * delegate, and if not, then if js_NewFunction flagged obj as a delegate,
2878 * we clear the flag.
2880 * We thus rely on the fact that native functions (including indirect eval)
2881 * do not use the property cache or equivalent JIT techniques that require
2882 * this bit to be set on their parent-linked scope chain objects.
2884 * Note: we keep API compatibility by setting parent to obj for all native
2885 * function objects, even if obj->getGlobal() would suffice. This should be
2886 * revisited when parent is narrowed to exist only for function objects and
2887 * possibly a few prehistoric scope objects (e.g. event targets).
2889 * FIXME: bug 611190.
2891 bool wasDelegate
= obj
->isDelegate();
2893 fun
= js_NewFunction(cx
, NULL
, native
, nargs
,
2894 attrs
& (JSFUN_FLAGS_MASK
| JSFUN_TRCINFO
),
2896 JSID_IS_ATOM(id
) ? JSID_TO_ATOM(id
) : NULL
);
2900 if (!wasDelegate
&& obj
->isDelegate())
2901 obj
->clearDelegate();
2903 if (!obj
->defineProperty(cx
, id
, ObjectValue(*fun
), gsop
, gsop
, attrs
& ~JSFUN_FLAGS_MASK
))
2908 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2909 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2913 js_ValueToFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
2916 if (!IsFunctionObject(*vp
, &funobj
)) {
2917 js_ReportIsNotFunction(cx
, vp
, flags
);
2920 return GET_FUNCTION_PRIVATE(cx
, funobj
);
2924 js_ValueToFunctionObject(JSContext
*cx
, Value
*vp
, uintN flags
)
2927 if (!IsFunctionObject(*vp
, &funobj
)) {
2928 js_ReportIsNotFunction(cx
, vp
, flags
);
2936 js_ValueToCallableObject(JSContext
*cx
, Value
*vp
, uintN flags
)
2938 if (vp
->isObject()) {
2939 JSObject
*callable
= &vp
->toObject();
2940 if (callable
->isCallable())
2944 js_ReportIsNotFunction(cx
, vp
, flags
);
2949 js_ReportIsNotFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
2951 const char *name
= NULL
, *source
= NULL
;
2952 AutoValueRooter
tvr(cx
);
2953 uintN error
= (flags
& JSV2F_CONSTRUCT
) ? JSMSG_NOT_CONSTRUCTOR
: JSMSG_NOT_FUNCTION
;
2957 * We try to the print the code that produced vp if vp is a value in the
2958 * most recent interpreted stack frame. Note that additional values, not
2959 * directly produced by the script, may have been pushed onto the frame's
2960 * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
2961 * the depth simulated by ReconstructPCStack.
2963 * Conversely, values may have been popped from the stack in preparation
2964 * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from
2965 * the top of the simulated stack to js_ReportValueError3, we do bounds
2966 * checking using the minimum of both the simulated and actual stack depth.
2968 ptrdiff_t spindex
= 0;
2970 FrameRegsIter
i(cx
);
2971 while (!i
.done() && !i
.pc())
2975 uintN depth
= js_ReconstructStackDepth(cx
, i
.fp()->script(), i
.pc());
2976 Value
*simsp
= i
.fp()->base() + depth
;
2977 if (i
.fp()->base() <= vp
&& vp
< Min(simsp
, i
.sp()))
2978 spindex
= vp
- simsp
;
2982 spindex
= ((flags
& JSV2F_SEARCH_STACK
) ? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK
);
2984 js_ReportValueError3(cx
, error
, spindex
, *vp
, NULL
, name
, source
);