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
->compartment
->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
408 script
->getVersion());
412 memcpy(wscript
->code
, script
->code
, script
->length
);
413 wscript
->main
= wscript
->code
+ (script
->main
- script
->code
);
415 memcpy(wscript
->notes(), snbase
, nsrcnotes
* sizeof(jssrcnote
));
416 memcpy(wscript
->atomMap
.vector
, script
->atomMap
.vector
,
417 wscript
->atomMap
.length
* sizeof(JSAtom
*));
418 if (JSScript::isValidOffset(script
->objectsOffset
)) {
419 memcpy(wscript
->objects()->vector
, script
->objects()->vector
,
420 wscript
->objects()->length
* sizeof(JSObject
*));
422 if (JSScript::isValidOffset(script
->regexpsOffset
)) {
423 memcpy(wscript
->regexps()->vector
, script
->regexps()->vector
,
424 wscript
->regexps()->length
* sizeof(JSObject
*));
426 if (JSScript::isValidOffset(script
->trynotesOffset
)) {
427 memcpy(wscript
->trynotes()->vector
, script
->trynotes()->vector
,
428 wscript
->trynotes()->length
* sizeof(JSTryNote
));
430 if (JSScript::isValidOffset(script
->globalsOffset
)) {
431 memcpy(wscript
->globals()->vector
, script
->globals()->vector
,
432 wscript
->globals()->length
* sizeof(GlobalSlotArray::Entry
));
434 if (script
->nClosedArgs
+ script
->nClosedVars
!= 0)
435 script
->copyClosedSlotsTo(wscript
);
437 if (script
->bindings
.hasUpvars()) {
438 JS_ASSERT(script
->bindings
.countUpvars() == wscript
->upvars()->length
);
439 memcpy(wscript
->upvars()->vector
, script
->upvars()->vector
,
440 script
->bindings
.countUpvars() * sizeof(uint32
));
443 jsbytecode
*pc
= wscript
->code
;
444 while (*pc
!= JSOP_STOP
) {
445 /* FIXME should copy JSOP_TRAP? */
446 JSOp op
= js_GetOpcode(cx
, wscript
, pc
);
447 const JSCodeSpec
*cs
= &js_CodeSpec
[op
];
448 ptrdiff_t oplen
= cs
->length
;
450 oplen
= js_GetVariableBytecodeLength(pc
);
453 * Rewrite JSOP_{GET,CALL}FCSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
454 * case where fun is an escaping flat closure. This works because the
455 * UPVAR and FCSLOT ops by design have the same format: an upvar index
459 case JSOP_GETFCSLOT
: *pc
= JSOP_GETUPVAR_DBG
; break;
460 case JSOP_CALLFCSLOT
: *pc
= JSOP_CALLUPVAR_DBG
; break;
461 case JSOP_DEFFUN_FC
: *pc
= JSOP_DEFFUN_DBGFC
; break;
462 case JSOP_DEFLOCALFUN_FC
: *pc
= JSOP_DEFLOCALFUN_DBGFC
; break;
463 case JSOP_LAMBDA_FC
: *pc
= JSOP_LAMBDA_DBGFC
; break;
470 * Fill in the rest of wscript. This means if you add members to JSScript
471 * you must update this code. FIXME: factor into JSScript::clone method.
473 JS_ASSERT(wscript
->getVersion() == script
->getVersion());
474 wscript
->nfixed
= script
->nfixed
;
475 wscript
->filename
= script
->filename
;
476 wscript
->lineno
= script
->lineno
;
477 wscript
->nslots
= script
->nslots
;
478 wscript
->staticLevel
= script
->staticLevel
;
479 wscript
->principals
= script
->principals
;
480 wscript
->noScriptRval
= script
->noScriptRval
;
481 wscript
->savedCallerFun
= script
->savedCallerFun
;
482 wscript
->hasSharps
= script
->hasSharps
;
483 wscript
->strictModeCode
= script
->strictModeCode
;
484 wscript
->compileAndGo
= script
->compileAndGo
;
485 wscript
->usesEval
= script
->usesEval
;
486 wscript
->usesArguments
= script
->usesArguments
;
487 wscript
->warnedAboutTwoArgumentEval
= script
->warnedAboutTwoArgumentEval
;
488 if (wscript
->principals
)
489 JSPRINCIPALS_HOLD(cx
, wscript
->principals
);
490 #ifdef CHECK_SCRIPT_OWNER
491 wscript
->owner
= script
->owner
;
494 wscript
->bindings
.clone(cx
, &script
->bindings
);
496 /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
497 FUN_SET_KIND(wfun
, JSFUN_INTERPRETED
);
498 wfun
->u
.i
.script
= wscript
;
503 ArgGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
507 if (!InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
510 if (JSID_IS_INT(id
)) {
512 * arg can exceed the number of arguments if a script changed the
513 * prototype to point to another Arguments object with a bigger argc.
515 uintN arg
= uintN(JSID_TO_INT(id
));
516 if (arg
< obj
->getArgsInitialLength()) {
517 JS_ASSERT(!obj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
));
518 if (JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate())
519 *vp
= fp
->canonicalActualArg(arg
);
521 *vp
= obj
->getArgsElement(arg
);
523 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
524 if (!obj
->isArgsLengthOverridden())
525 vp
->setInt32(obj
->getArgsInitialLength());
527 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
));
528 const Value
&v
= obj
->getArgsCallee();
529 if (!v
.isMagic(JS_ARGS_HOLE
)) {
531 * If this function or one in it needs upvars that reach above it
532 * in the scope chain, it must not be a null closure (it could be a
533 * flat closure, or an unoptimized closure -- the latter itself not
534 * necessarily heavyweight). Rather than wrap here, we simply throw
535 * to reduce code size and tell debugger users the truth instead of
536 * passing off a fibbing wrapper.
538 if (GET_FUNCTION_PRIVATE(cx
, &v
.toObject())->needsWrapper()) {
539 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
540 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
550 ArgSetter(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
553 // To be able to set a property here on trace, we would have to make
554 // sure any updates also get written back to the trace native stack.
555 // For simplicity, we just leave trace, since this is presumably not
556 // a common operation.
560 if (!InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
563 if (JSID_IS_INT(id
)) {
564 uintN arg
= uintN(JSID_TO_INT(id
));
565 if (arg
< obj
->getArgsInitialLength()) {
566 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
568 JSScript
*script
= fp
->functionScript();
569 if (script
->usesArguments
)
570 fp
->canonicalActualArg(arg
) = *vp
;
575 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
) ||
576 JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
));
580 * For simplicity we use delete/define to replace the property with one
581 * backed by the default Object getter and setter. Note that we rely on
582 * args_delProperty to clear the corresponding reserved slot so the GC can
583 * collect its value. Note also that we must define the property instead
584 * of setting it in case the user has changed the prototype to an object
585 * that has a setter for this id.
587 AutoValueRooter
tvr(cx
);
588 return js_DeleteProperty(cx
, obj
, id
, tvr
.addr(), false) &&
589 js_DefineProperty(cx
, obj
, id
, vp
, NULL
, NULL
, JSPROP_ENUMERATE
);
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());
680 StrictArgSetter(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
682 if (!InstanceOf(cx
, obj
, &StrictArgumentsClass
, NULL
))
685 if (JSID_IS_INT(id
)) {
686 uintN arg
= uintN(JSID_TO_INT(id
));
687 if (arg
< obj
->getArgsInitialLength()) {
688 obj
->setArgsElement(arg
, *vp
);
692 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
));
696 * For simplicity we use delete/set to replace the property with one
697 * backed by the default Object getter and setter. Note that we rely on
698 * args_delProperty to clear the corresponding reserved slot so the GC can
701 AutoValueRooter
tvr(cx
);
702 return js_DeleteProperty(cx
, obj
, id
, tvr
.addr(), strict
) &&
703 js_SetProperty(cx
, obj
, id
, vp
, strict
);
707 strictargs_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
, JSObject
**objp
)
709 JS_ASSERT(obj
->isStrictArguments());
713 uintN attrs
= JSPROP_SHARED
| JSPROP_SHADOWABLE
;
714 PropertyOp getter
= StrictArgGetter
;
715 StrictPropertyOp setter
= StrictArgSetter
;
717 if (JSID_IS_INT(id
)) {
718 uint32 arg
= uint32(JSID_TO_INT(id
));
719 if (arg
>= obj
->getArgsInitialLength() || obj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
722 attrs
|= JSPROP_ENUMERATE
;
723 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
724 if (obj
->isArgsLengthOverridden())
727 if (!JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
) &&
728 !JSID_IS_ATOM(id
, cx
->runtime
->atomState
.callerAtom
)) {
732 attrs
= JSPROP_PERMANENT
| JSPROP_GETTER
| JSPROP_SETTER
| JSPROP_SHARED
;
733 getter
= CastAsPropertyOp(obj
->getThrowTypeError());
734 setter
= CastAsStrictPropertyOp(obj
->getThrowTypeError());
737 Value undef
= UndefinedValue();
738 if (!js_DefineProperty(cx
, obj
, id
, &undef
, getter
, setter
, attrs
))
746 strictargs_enumerate(JSContext
*cx
, JSObject
*obj
)
748 JS_ASSERT(obj
->isStrictArguments());
751 * Trigger reflection in strictargs_resolve using a series of
752 * js_LookupProperty calls.
758 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
), &pobj
, &prop
))
762 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
), &pobj
, &prop
))
766 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.callerAtom
), &pobj
, &prop
))
769 for (uint32 i
= 0, argc
= obj
->getArgsInitialLength(); i
< argc
; i
++) {
770 if (!js_LookupProperty(cx
, obj
, INT_TO_JSID(i
), &pobj
, &prop
))
778 args_finalize(JSContext
*cx
, JSObject
*obj
)
780 cx
->free((void *) obj
->getArgsData());
784 * If a generator's arguments or call object escapes, and the generator frame
785 * is not executing, the generator object needs to be marked because it is not
786 * otherwise reachable. An executing generator is rooted by its invocation. To
787 * distinguish the two cases (which imply different access paths to the
788 * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
789 * set on the JSStackFrame kept in the generator object's JSGenerator.
792 MaybeMarkGenerator(JSTracer
*trc
, JSObject
*obj
)
794 #if JS_HAS_GENERATORS
795 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
796 if (fp
&& fp
->isFloatingGenerator()) {
797 JSObject
*genobj
= js_FloatingFrameToGenerator(fp
)->obj
;
798 MarkObject(trc
, *genobj
, "generator object");
804 args_trace(JSTracer
*trc
, JSObject
*obj
)
806 JS_ASSERT(obj
->isArguments());
807 if (obj
->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE
) {
808 JS_ASSERT(!obj
->isStrictArguments());
812 ArgumentsData
*data
= obj
->getArgsData();
813 if (data
->callee
.isObject())
814 MarkObject(trc
, data
->callee
.toObject(), js_callee_str
);
815 MarkValueRange(trc
, obj
->getArgsInitialLength(), data
->slots
, js_arguments_str
);
817 MaybeMarkGenerator(trc
, obj
);
821 * The Arguments classes aren't initialized via js_InitClass, because arguments
822 * objects have the initial value of Object.prototype as their [[Prototype]].
823 * However, Object.prototype.toString.call(arguments) === "[object Arguments]"
824 * per ES5 (although not ES3), so the class name is "Arguments" rather than
827 * The JSClass functions below collaborate to lazily reflect and synchronize
828 * actual argument values, argument count, and callee function object stored
829 * in a JSStackFrame with their corresponding property values in the frame's
832 Class js_ArgumentsClass
= {
834 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
835 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
836 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
837 PropertyStub
, /* addProperty */
839 PropertyStub
, /* getProperty */
840 StrictPropertyStub
, /* setProperty */
842 (JSResolveOp
) args_resolve
,
844 args_finalize
, /* finalize */
845 NULL
, /* reserved0 */
846 NULL
, /* checkAccess */
848 NULL
, /* construct */
849 NULL
, /* xdrObject */
850 NULL
, /* hasInstance */
851 JS_CLASS_TRACE(args_trace
)
857 * Strict mode arguments is significantly less magical than non-strict mode
858 * arguments, so it is represented by a different class while sharing some
861 Class StrictArgumentsClass
= {
863 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
864 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
865 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
866 PropertyStub
, /* addProperty */
868 PropertyStub
, /* getProperty */
869 StrictPropertyStub
, /* setProperty */
870 strictargs_enumerate
,
871 reinterpret_cast<JSResolveOp
>(strictargs_resolve
),
873 args_finalize
, /* finalize */
874 NULL
, /* reserved0 */
875 NULL
, /* checkAccess */
877 NULL
, /* construct */
878 NULL
, /* xdrObject */
879 NULL
, /* hasInstance */
880 JS_CLASS_TRACE(args_trace
)
886 * A Declarative Environment object stores its active JSStackFrame pointer in
887 * its private slot, just as Call and Arguments objects do.
889 Class js_DeclEnvClass
= {
891 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
892 PropertyStub
, /* addProperty */
893 PropertyStub
, /* delProperty */
894 PropertyStub
, /* getProperty */
895 StrictPropertyStub
, /* setProperty */
902 CheckForEscapingClosure(JSContext
*cx
, JSObject
*obj
, Value
*vp
)
904 JS_ASSERT(obj
->isCall() || obj
->getClass() == &js_DeclEnvClass
);
906 const Value
&v
= *vp
;
909 if (IsFunctionObject(v
, &funobj
)) {
910 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
913 * Any escaping null or flat closure that reaches above itself or
914 * contains nested functions that reach above it must be wrapped.
915 * We can wrap only when this Call or Declarative Environment obj
916 * still has an active stack frame associated with it.
918 if (fun
->needsWrapper()) {
921 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
923 JSObject
*wrapper
= WrapEscapingClosure(cx
, fp
, fun
);
926 vp
->setObject(*wrapper
);
930 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
931 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
939 CalleeGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
941 return CheckForEscapingClosure(cx
, obj
, vp
);
947 * Construct a call object for the given bindings. The callee is the function
948 * on behalf of which the call object is being created.
951 NewCallObject(JSContext
*cx
, Bindings
*bindings
, JSObject
&scopeChain
, JSObject
*callee
)
953 size_t argsVars
= bindings
->countArgsAndVars();
954 size_t slots
= JSObject::CALL_RESERVED_SLOTS
+ argsVars
;
955 gc::FinalizeKind kind
= gc::GetGCObjectKind(slots
);
957 JSObject
*callobj
= js_NewGCObject(cx
, kind
);
961 /* Init immediately to avoid GC seeing a half-init'ed object. */
962 callobj
->init(cx
, &js_CallClass
, NULL
, &scopeChain
, NULL
, false);
963 callobj
->setMap(bindings
->lastShape());
965 /* This must come after callobj->lastProp has been set. */
966 if (!callobj
->ensureInstanceReservedSlots(cx
, argsVars
))
970 for (Shape::Range r
= callobj
->lastProp
; !r
.empty(); r
.popFront()) {
971 const Shape
&s
= r
.front();
972 if (s
.slot
!= SHAPE_INVALID_SLOT
) {
973 JS_ASSERT(s
.slot
+ 1 == callobj
->slotSpan());
979 callobj
->setCallObjCallee(callee
);
985 static inline JSObject
*
986 NewDeclEnvObject(JSContext
*cx
, JSStackFrame
*fp
)
988 JSObject
*envobj
= js_NewGCObject(cx
, FINALIZE_OBJECT2
);
992 envobj
->init(cx
, &js_DeclEnvClass
, NULL
, &fp
->scopeChain(), fp
, false);
993 envobj
->setMap(cx
->compartment
->emptyDeclEnvShape
);
998 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1000 /* Create a call object for fp only if it lacks one. */
1001 JS_ASSERT(fp
->isFunctionFrame());
1002 if (fp
->hasCallObj())
1003 return &fp
->callObj();
1006 /* A call object should be a frame's outermost scope chain element. */
1007 Class
*clasp
= fp
->scopeChain().getClass();
1008 if (clasp
== &js_WithClass
|| clasp
== &js_BlockClass
)
1009 JS_ASSERT(fp
->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx
, fp
));
1010 else if (clasp
== &js_CallClass
)
1011 JS_ASSERT(fp
->scopeChain().getPrivate() != fp
);
1015 * Create the call object, using the frame's enclosing scope as its
1016 * parent, and link the call to its stack frame. For a named function
1017 * expression Call's parent points to an environment object holding
1020 JSAtom
*lambdaName
=
1021 (fp
->fun()->flags
& JSFUN_LAMBDA
) ? fp
->fun()->atom
: NULL
;
1023 JSObject
*envobj
= NewDeclEnvObject(cx
, fp
);
1027 /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
1028 fp
->setScopeChainNoCallObj(*envobj
);
1029 if (!js_DefineNativeProperty(cx
, &fp
->scopeChain(), ATOM_TO_JSID(lambdaName
),
1030 ObjectValue(fp
->callee()),
1032 JSPROP_PERMANENT
| JSPROP_READONLY
,
1039 NewCallObject(cx
, &fp
->fun()->script()->bindings
, fp
->scopeChain(), &fp
->callee());
1043 callobj
->setPrivate(fp
);
1044 JS_ASSERT(fp
->fun() == fp
->callee().getFunctionPrivate());
1047 * Push callobj on the top of the scope chain, and make it the
1050 fp
->setScopeChainAndCallObj(*callobj
);
1054 JSObject
* JS_FASTCALL
1055 js_CreateCallObjectOnTrace(JSContext
*cx
, JSFunction
*fun
, JSObject
*callee
, JSObject
*scopeChain
)
1057 JS_ASSERT(!js_IsNamedLambda(fun
));
1058 JS_ASSERT(scopeChain
);
1060 return NewCallObject(cx
, &fun
->script()->bindings
, *scopeChain
, callee
);
1063 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CreateCallObjectOnTrace
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
,
1064 0, nanojit::ACCSET_STORE_ANY
)
1067 CopyValuesToCallObject(JSObject
&callobj
, uintN nargs
, Value
*argv
, uintN nvars
, Value
*slots
)
1069 JS_ASSERT(callobj
.numSlots() >= JSObject::CALL_RESERVED_SLOTS
+ nargs
+ nvars
);
1070 Value
*base
= callobj
.getSlots() + JSObject::CALL_RESERVED_SLOTS
;
1071 memcpy(base
, argv
, nargs
* sizeof(Value
));
1072 memcpy(base
+ nargs
, slots
, nvars
* sizeof(Value
));
1076 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1078 JSObject
&callobj
= fp
->callObj();
1081 * Strict mode eval frames have Call objects to put. Normal eval frames
1082 * never put a Call object.
1084 JS_ASSERT(fp
->isEvalFrame() == callobj
.callIsForEval());
1086 /* Get the arguments object to snapshot fp's actual argument values. */
1087 if (fp
->hasArgsObj()) {
1088 if (!fp
->hasOverriddenArgs())
1089 callobj
.setCallObjArguments(ObjectValue(fp
->argsObj()));
1090 js_PutArgsObject(cx
, fp
);
1093 JSScript
*script
= fp
->script();
1094 Bindings
&bindings
= script
->bindings
;
1096 if (callobj
.callIsForEval()) {
1097 JS_ASSERT(script
->strictModeCode
);
1098 JS_ASSERT(bindings
.countArgs() == 0);
1100 /* This could be optimized as below, but keep it simple for now. */
1101 CopyValuesToCallObject(callobj
, 0, NULL
, bindings
.countVars(), fp
->slots());
1103 JSFunction
*fun
= fp
->fun();
1104 JS_ASSERT(fun
== callobj
.getCallObjCalleeFunction());
1105 JS_ASSERT(script
== fun
->script());
1107 uintN n
= bindings
.countArgsAndVars();
1109 JS_ASSERT(JSObject::CALL_RESERVED_SLOTS
+ n
<= callobj
.numSlots());
1111 uint32 nvars
= bindings
.countVars();
1112 uint32 nargs
= bindings
.countArgs();
1113 JS_ASSERT(fun
->nargs
== nargs
);
1114 JS_ASSERT(nvars
+ nargs
== n
);
1116 JSScript
*script
= fun
->script();
1117 if (script
->usesEval
1119 || script
->debugMode
1122 CopyValuesToCallObject(callobj
, nargs
, fp
->formalArgs(), nvars
, fp
->slots());
1125 * For each arg & var that is closed over, copy it from the stack
1126 * into the call object.
1128 uint32 nclosed
= script
->nClosedArgs
;
1129 for (uint32 i
= 0; i
< nclosed
; i
++) {
1130 uint32 e
= script
->getClosedArg(i
);
1131 callobj
.setSlot(JSObject::CALL_RESERVED_SLOTS
+ e
, fp
->formalArg(e
));
1134 nclosed
= script
->nClosedVars
;
1135 for (uint32 i
= 0; i
< nclosed
; i
++) {
1136 uint32 e
= script
->getClosedVar(i
);
1137 callobj
.setSlot(JSObject::CALL_RESERVED_SLOTS
+ nargs
+ e
, fp
->slots()[e
]);
1142 /* Clear private pointers to fp, which is about to go away (js_Invoke). */
1143 if (js_IsNamedLambda(fun
)) {
1144 JSObject
*env
= callobj
.getParent();
1146 JS_ASSERT(env
->getClass() == &js_DeclEnvClass
);
1147 JS_ASSERT(env
->getPrivate() == fp
);
1148 env
->setPrivate(NULL
);
1152 callobj
.setPrivate(NULL
);
1157 js_PutCallObjectOnTrace(JSContext
*cx
, JSObject
*callobj
, uint32 nargs
, Value
*argv
,
1158 uint32 nvars
, Value
*slots
)
1160 JS_ASSERT(callobj
->isCall());
1161 JS_ASSERT(!callobj
->getPrivate());
1163 uintN n
= nargs
+ nvars
;
1165 CopyValuesToCallObject(*callobj
, nargs
, argv
, nvars
, slots
);
1170 JS_DEFINE_CALLINFO_6(extern, BOOL
, js_PutCallObjectOnTrace
, CONTEXT
, OBJECT
, UINT32
, VALUEPTR
,
1171 UINT32
, VALUEPTR
, 0, nanojit::ACCSET_STORE_ANY
)
1176 GetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1178 JSStackFrame
*fp
= obj
->maybeCallObjStackFrame();
1179 if (fp
&& !fp
->hasOverriddenArgs()) {
1180 JSObject
*argsobj
= js_GetArgsObject(cx
, fp
);
1183 vp
->setObject(*argsobj
);
1185 *vp
= obj
->getCallObjArguments();
1191 SetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
1193 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1194 fp
->setOverriddenArgs();
1195 obj
->setCallObjArguments(*vp
);
1200 GetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1202 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1203 uintN i
= (uint16
) JSID_TO_INT(id
);
1205 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1206 *vp
= fp
->formalArg(i
);
1208 *vp
= obj
->callObjArg(i
);
1213 SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
1215 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1216 uintN i
= (uint16
) JSID_TO_INT(id
);
1219 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1220 argp
= &fp
->formalArg(i
);
1222 argp
= &obj
->callObjArg(i
);
1230 GetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1232 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1233 uintN i
= (uint16
) JSID_TO_INT(id
);
1235 *vp
= obj
->getCallObjCallee()->getFlatClosureUpvar(i
);
1240 SetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
1242 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1243 uintN i
= (uint16
) JSID_TO_INT(id
);
1245 Value
*up
= &obj
->getCallObjCallee()->getFlatClosureUpvar(i
);
1253 GetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1255 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1256 uintN i
= (uint16
) JSID_TO_INT(id
);
1258 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1259 *vp
= fp
->varSlot(i
);
1261 *vp
= obj
->callObjVar(i
);
1267 GetCallVarChecked(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1269 if (!GetCallVar(cx
, obj
, id
, vp
))
1272 return CheckForEscapingClosure(cx
, obj
, vp
);
1276 SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
1278 JS_ASSERT(obj
->isCall());
1280 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1281 uintN i
= (uint16
) JSID_TO_INT(id
);
1284 * As documented in TraceRecorder::attemptTreeCall(), when recording an
1285 * inner tree call, the recorder assumes the inner tree does not mutate
1286 * any tracked upvars. The abort here is a pessimistic precaution against
1287 * bug 620662, where an inner tree setting a closed stack variable in an
1288 * outer tree is illegal, and runtime would fall off trace.
1291 if (JS_ON_TRACE(cx
)) {
1292 TraceMonitor
*tm
= JS_TRACE_MONITOR_ON_TRACE(cx
);
1293 if (tm
->recorder
&& tm
->tracecx
)
1294 AbortRecording(cx
, "upvar write in nested tree");
1299 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame())
1300 varp
= &fp
->varSlot(i
);
1302 varp
= &obj
->callObjVar(i
);
1313 js_SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1315 Value argcopy
= ValueArgToConstRef(arg
);
1316 return SetCallArg(cx
, obj
, slotid
, false /* STRICT DUMMY */, &argcopy
);
1318 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallArg
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1319 nanojit::ACCSET_STORE_ANY
)
1322 js_SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1324 Value argcopy
= ValueArgToConstRef(arg
);
1325 return SetCallVar(cx
, obj
, slotid
, false /* STRICT DUMMY */, &argcopy
);
1327 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallVar
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1328 nanojit::ACCSET_STORE_ANY
)
1332 call_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1335 JS_ASSERT(obj
->isCall());
1336 JS_ASSERT(!obj
->getProto());
1338 if (!JSID_IS_ATOM(id
))
1341 JSObject
*callee
= obj
->getCallObjCallee();
1344 JSScript
*script
= callee
->getFunctionPrivate()->script();
1345 JS_ASSERT(!script
->bindings
.hasBinding(cx
, JSID_TO_ATOM(id
)));
1350 * Resolve arguments so that we never store a particular Call object's
1351 * arguments object reference in a Call prototype's |arguments| slot.
1353 * Include JSPROP_ENUMERATE for consistency with all other Call object
1354 * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
1355 * rebinding-Call-property logic.
1357 if (callee
&& id
== ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
)) {
1358 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1359 GetCallArguments
, SetCallArguments
,
1360 JSPROP_PERMANENT
| JSPROP_SHARED
| JSPROP_ENUMERATE
,
1361 0, 0, NULL
, JSDNP_DONT_PURGE
)) {
1368 /* Control flow reaches here only if id was not resolved. */
1373 call_trace(JSTracer
*trc
, JSObject
*obj
)
1375 JS_ASSERT(obj
->isCall());
1376 if (JSStackFrame
*fp
= obj
->maybeCallObjStackFrame()) {
1378 * FIXME: Hide copies of stack values rooted by fp from the Cycle
1379 * Collector, which currently lacks a non-stub Unlink implementation
1380 * for JS objects (including Call objects), so is unable to collect
1381 * cycles involving Call objects whose frames are active without this
1384 uintN first
= JSObject::CALL_RESERVED_SLOTS
;
1385 uintN count
= fp
->script()->bindings
.countArgsAndVars();
1387 JS_ASSERT(obj
->numSlots() >= first
+ count
);
1388 SetValueRangeToUndefined(obj
->getSlots() + first
, count
);
1391 MaybeMarkGenerator(trc
, obj
);
1394 JS_PUBLIC_DATA(Class
) js_CallClass
= {
1396 JSCLASS_HAS_PRIVATE
|
1397 JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS
) |
1398 JSCLASS_NEW_RESOLVE
| JSCLASS_IS_ANONYMOUS
| JSCLASS_MARK_IS_TRACE
,
1399 PropertyStub
, /* addProperty */
1400 PropertyStub
, /* delProperty */
1401 PropertyStub
, /* getProperty */
1402 StrictPropertyStub
, /* setProperty */
1404 (JSResolveOp
)call_resolve
,
1405 NULL
, /* convert: Leave it NULL so we notice if calls ever escape */
1406 NULL
, /* finalize */
1407 NULL
, /* reserved0 */
1408 NULL
, /* checkAccess */
1410 NULL
, /* construct */
1411 NULL
, /* xdrObject */
1412 NULL
, /* hasInstance */
1413 JS_CLASS_TRACE(call_trace
)
1417 JSStackFrame::getValidCalleeObject(JSContext
*cx
, Value
*vp
)
1419 if (!isFunctionFrame()) {
1424 JSFunction
*fun
= this->fun();
1427 * See the equivalent condition in ArgGetter for the 'callee' id case, but
1428 * note that here we do not want to throw, since this escape can happen via
1429 * a foo.caller reference alone, without any debugger or indirect eval. And
1430 * alas, it seems foo.caller is still used on the Web.
1432 if (fun
->needsWrapper()) {
1433 JSObject
*wrapper
= WrapEscapingClosure(cx
, this, fun
);
1436 vp
->setObject(*wrapper
);
1440 JSObject
&funobj
= callee();
1441 vp
->setObject(funobj
);
1444 * Check for an escape attempt by a joined function object, which must go
1445 * through the frame's |this| object's method read barrier for the method
1446 * atom by which it was uniquely associated with a property.
1448 const Value
&thisv
= functionThis();
1449 if (thisv
.isObject()) {
1450 JS_ASSERT(funobj
.getFunctionPrivate() == fun
);
1452 if (&fun
->compiledFunObj() == &funobj
&& fun
->methodAtom()) {
1453 JSObject
*thisp
= &thisv
.toObject();
1454 JSObject
*first_barriered_thisp
= NULL
;
1458 * While a non-native object is responsible for handling its
1459 * entire prototype chain, notable non-natives including dense
1460 * and typed arrays have native prototypes, so keep going.
1462 if (!thisp
->isNative())
1465 if (thisp
->hasMethodBarrier()) {
1466 const Shape
*shape
= thisp
->nativeLookup(ATOM_TO_JSID(fun
->methodAtom()));
1469 * Two cases follow: the method barrier was not crossed
1470 * yet, so we cross it here; the method barrier *was*
1471 * crossed but after the call, in which case we fetch
1472 * and validate the cloned (unjoined) funobj from the
1473 * method property's slot.
1475 * In either case we must allow for the method property
1476 * to have been replaced, or its value overwritten.
1478 if (shape
->isMethod() && &shape
->methodObject() == &funobj
) {
1479 if (!thisp
->methodReadBarrier(cx
, *shape
, vp
))
1481 calleeValue().setObject(vp
->toObject());
1485 if (shape
->hasSlot()) {
1486 Value v
= thisp
->getSlot(shape
->slot
);
1489 if (IsFunctionObject(v
, &clone
) &&
1490 GET_FUNCTION_PRIVATE(cx
, clone
) == fun
&&
1491 clone
->hasMethodObj(*thisp
)) {
1492 JS_ASSERT(clone
!= &funobj
);
1494 calleeValue().setObject(*clone
);
1500 if (!first_barriered_thisp
)
1501 first_barriered_thisp
= thisp
;
1503 } while ((thisp
= thisp
->getProto()) != NULL
);
1505 if (!first_barriered_thisp
)
1509 * At this point, we couldn't find an already-existing clone (or
1510 * force to exist a fresh clone) created via thisp's method read
1511 * barrier, so we must clone fun and store it in fp's callee to
1512 * avoid re-cloning upon repeated foo.caller access.
1514 * This must mean the code in js_DeleteProperty could not find this
1515 * stack frame on the stack when the method was deleted. We've lost
1516 * track of the method, so we associate it with the first barriered
1517 * object found starting from thisp on the prototype chain.
1519 JSObject
*newfunobj
= CloneFunctionObject(cx
, fun
, fun
->getParent());
1522 newfunobj
->setMethodObj(*first_barriered_thisp
);
1523 calleeValue().setObject(*newfunobj
);
1524 vp
->setObject(*newfunobj
);
1532 /* Generic function tinyids. */
1534 FUN_ARGUMENTS
= -1, /* predefined arguments local variable */
1535 FUN_LENGTH
= -2, /* number of actual args, arity if inactive */
1536 FUN_ARITY
= -3, /* number of formal parameters; desired argc */
1537 FUN_NAME
= -4, /* function name, "" if anonymous */
1538 FUN_CALLER
= -5 /* Function.prototype.caller, backward compat */
1542 fun_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1544 if (!JSID_IS_INT(id
))
1547 jsint slot
= JSID_TO_INT(id
);
1550 * Loop because getter and setter can be delegated from another class,
1551 * but loop only for FUN_LENGTH because we must pretend that f.length
1552 * is in each function instance f, per ECMA-262, instead of only in the
1553 * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1554 * to make it appear so).
1556 * This code couples tightly to the attributes for lazyFunctionDataProps[]
1557 * and poisonPillProps[] initializers below, and to js_SetProperty and
1558 * js_HasOwnProperty.
1560 * It's important to allow delegating objects, even though they inherit
1561 * this getter (fun_getProperty), to override arguments, arity, caller,
1562 * and name. If we didn't return early for slot != FUN_LENGTH, we would
1563 * clobber *vp with the native property value, instead of letting script
1564 * override that value in delegating objects.
1566 * Note how that clobbering is what simulates JSPROP_READONLY for all of
1567 * the non-standard properties when the directly addressed object (obj)
1568 * is a function object (i.e., when this loop does not iterate).
1571 while (!(fun
= (JSFunction
*)
1572 GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
))) {
1573 if (slot
!= FUN_LENGTH
)
1575 obj
= obj
->getProto();
1580 /* Find fun's top-most activation record. */
1582 for (fp
= js_GetTopStackFrame(cx
);
1583 fp
&& (fp
->maybeFun() != fun
|| fp
->isEvalOrDebuggerFrame());
1590 /* Warn if strict about f.arguments or equivalent unqualified uses. */
1591 if (!JS_ReportErrorFlagsAndNumber(cx
,
1592 JSREPORT_WARNING
| JSREPORT_STRICT
,
1593 js_GetErrorMessage
, NULL
,
1594 JSMSG_DEPRECATED_USAGE
,
1595 js_arguments_str
)) {
1599 if (!js_GetArgsValue(cx
, fp
, vp
))
1608 vp
->setInt32(fun
->nargs
);
1612 vp
->setString(fun
->atom
? ATOM_TO_STRING(fun
->atom
)
1613 : cx
->runtime
->emptyString
);
1618 if (fp
&& fp
->prev() && !fp
->prev()->getValidCalleeObject(cx
, vp
))
1621 if (vp
->isObject()) {
1622 JSObject
&caller
= vp
->toObject();
1624 /* Censor the caller if it is from another compartment. */
1625 if (caller
.getCompartment() != cx
->compartment
) {
1627 } else if (caller
.isFunction()) {
1628 JSFunction
*callerFun
= caller
.getFunctionPrivate();
1629 if (callerFun
->isInterpreted() && callerFun
->inStrictMode()) {
1630 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
1631 JSMSG_CALLER_IS_STRICT
);
1639 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1640 if (fp
&& fp
->isFunctionFrame() && uint16(slot
) < fp
->numFormalArgs())
1641 *vp
= fp
->formalArg(slot
);
1648 struct LazyFunctionDataProp
{
1654 struct PoisonPillProp
{
1659 /* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
1661 static const LazyFunctionDataProp lazyFunctionDataProps
[] = {
1662 {ATOM_OFFSET(arity
), FUN_ARITY
, JSPROP_PERMANENT
|JSPROP_READONLY
},
1663 {ATOM_OFFSET(name
), FUN_NAME
, JSPROP_PERMANENT
|JSPROP_READONLY
},
1666 /* Properties censored into [[ThrowTypeError]] in strict mode. */
1667 static const PoisonPillProp poisonPillProps
[] = {
1668 {ATOM_OFFSET(arguments
), FUN_ARGUMENTS
},
1669 {ATOM_OFFSET(caller
), FUN_CALLER
},
1673 fun_enumerate(JSContext
*cx
, JSObject
*obj
)
1675 JS_ASSERT(obj
->isFunction());
1680 if (!obj
->isBoundFunction()) {
1681 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1682 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1686 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
);
1687 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1690 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1691 const LazyFunctionDataProp
&lfp
= lazyFunctionDataProps
[i
];
1692 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, lfp
.atomOffset
));
1693 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1697 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(poisonPillProps
); i
++) {
1698 const PoisonPillProp
&p
= poisonPillProps
[i
];
1699 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
));
1700 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1708 ResolveInterpretedFunctionPrototype(JSContext
*cx
, JSObject
*obj
)
1711 JSFunction
*fun
= obj
->getFunctionPrivate();
1712 JS_ASSERT(fun
->isInterpreted());
1713 JS_ASSERT(!fun
->isFunctionPrototype());
1717 * Assert that fun is not a compiler-created function object, which
1718 * must never leak to script or embedding code and then be mutated.
1719 * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
1721 JS_ASSERT(!IsInternalFunctionObject(obj
));
1722 JS_ASSERT(!obj
->isBoundFunction());
1725 * Make the prototype object an instance of Object with the same parent
1726 * as the function object itself.
1728 JSObject
*parent
= obj
->getParent();
1730 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
1732 proto
= NewNativeClassInstance(cx
, &js_ObjectClass
, proto
, parent
);
1737 * ECMA (15.3.5.2) says that a user-defined function's .prototype property
1738 * is non-configurable, non-enumerable, and (initially) writable. Hence
1739 * JSPROP_PERMANENT below. By contrast, the built-in constructors, such as
1740 * Object (15.2.3.1) and Function (15.3.3.1), have non-writable
1741 * .prototype properties. Those are eagerly defined, with attributes
1742 * JSPROP_PERMANENT | JSPROP_READONLY, in js_InitClass.
1744 if (!js_SetClassPrototype(cx
, obj
, proto
, JSPROP_PERMANENT
))
1750 fun_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1753 if (!JSID_IS_ATOM(id
))
1756 JSFunction
*fun
= obj
->getFunctionPrivate();
1758 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.classPrototypeAtom
)) {
1760 * Native or "built-in" functions do not have a .prototype property per
1761 * ECMA-262 (all editions). Built-in constructor functions, e.g. Object
1762 * and Function to name two conspicuous examples, do have a .prototype
1763 * property, but it is created eagerly by js_InitClass (jsobj.cpp).
1765 * ES5 15.3.4: the non-native function object named Function.prototype
1766 * must not have a .prototype property.
1768 * ES5 15.3.4.5: bound functions don't have a prototype property. The
1769 * isNative() test covers this case because bound functions are native
1770 * functions by definition/construction.
1772 if (fun
->isNative() || fun
->isFunctionPrototype())
1775 if (!ResolveInterpretedFunctionPrototype(cx
, obj
))
1781 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
1782 JS_ASSERT(!IsInternalFunctionObject(obj
));
1783 if (!js_DefineNativeProperty(cx
, obj
, id
, Int32Value(fun
->nargs
),
1784 PropertyStub
, StrictPropertyStub
,
1785 JSPROP_PERMANENT
| JSPROP_READONLY
, 0, 0, NULL
)) {
1792 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1793 const LazyFunctionDataProp
*lfp
= &lazyFunctionDataProps
[i
];
1795 if (JSID_IS_ATOM(id
, OFFSET_TO_ATOM(cx
->runtime
, lfp
->atomOffset
))) {
1796 JS_ASSERT(!IsInternalFunctionObject(obj
));
1798 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1799 fun_getProperty
, StrictPropertyStub
,
1800 lfp
->attrs
, Shape::HAS_SHORTID
,
1801 lfp
->tinyid
, NULL
)) {
1809 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(poisonPillProps
); i
++) {
1810 const PoisonPillProp
&p
= poisonPillProps
[i
];
1812 if (JSID_IS_ATOM(id
, OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
))) {
1813 JS_ASSERT(!IsInternalFunctionObject(obj
));
1816 StrictPropertyOp setter
;
1817 uintN attrs
= JSPROP_PERMANENT
;
1818 if (fun
->isInterpreted() ? fun
->inStrictMode() : obj
->isBoundFunction()) {
1819 JSObject
*throwTypeError
= obj
->getThrowTypeError();
1821 getter
= CastAsPropertyOp(throwTypeError
);
1822 setter
= CastAsStrictPropertyOp(throwTypeError
);
1823 attrs
|= JSPROP_GETTER
| JSPROP_SETTER
;
1825 getter
= fun_getProperty
;
1826 setter
= StrictPropertyStub
;
1829 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1831 attrs
, Shape::HAS_SHORTID
,
1845 /* XXX store parent and proto, if defined */
1847 js_XDRFunctionObject(JSXDRState
*xdr
, JSObject
**objp
)
1851 uint32 firstword
; /* flag telling whether fun->atom is non-null,
1852 plus for fun->u.i.skipmin, fun->u.i.wrapper,
1853 and 14 bits reserved for future use */
1854 uint32 flagsword
; /* word for argument count and fun->flags */
1857 if (xdr
->mode
== JSXDR_ENCODE
) {
1858 fun
= GET_FUNCTION_PRIVATE(cx
, *objp
);
1859 if (!FUN_INTERPRETED(fun
)) {
1860 JSAutoByteString funNameBytes
;
1861 if (const char *name
= GetFunctionNameBytes(cx
, fun
, &funNameBytes
)) {
1862 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NOT_SCRIPTED_FUNCTION
,
1867 if (fun
->u
.i
.wrapper
) {
1868 JSAutoByteString funNameBytes
;
1869 if (const char *name
= GetFunctionNameBytes(cx
, fun
, &funNameBytes
))
1870 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_XDR_CLOSURE_WRAPPER
, name
);
1873 JS_ASSERT((fun
->u
.i
.wrapper
& ~1U) == 0);
1874 firstword
= (fun
->u
.i
.skipmin
<< 2) | (fun
->u
.i
.wrapper
<< 1) | !!fun
->atom
;
1875 flagsword
= (fun
->nargs
<< 16) | fun
->flags
;
1877 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, JSFUN_INTERPRETED
, NULL
, NULL
);
1880 FUN_OBJECT(fun
)->clearParent();
1881 FUN_OBJECT(fun
)->clearProto();
1884 AutoObjectRooter
tvr(cx
, FUN_OBJECT(fun
));
1886 if (!JS_XDRUint32(xdr
, &firstword
))
1888 if ((firstword
& 1U) && !js_XDRAtom(xdr
, &fun
->atom
))
1890 if (!JS_XDRUint32(xdr
, &flagsword
))
1893 if (xdr
->mode
== JSXDR_DECODE
) {
1894 fun
->nargs
= flagsword
>> 16;
1895 JS_ASSERT((flagsword
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
);
1896 fun
->flags
= uint16(flagsword
);
1897 fun
->u
.i
.skipmin
= uint16(firstword
>> 2);
1898 fun
->u
.i
.wrapper
= JSPackedBool((firstword
>> 1) & 1);
1901 if (!js_XDRScript(xdr
, &fun
->u
.i
.script
, NULL
))
1904 if (xdr
->mode
== JSXDR_DECODE
) {
1905 *objp
= FUN_OBJECT(fun
);
1906 #ifdef CHECK_SCRIPT_OWNER
1907 fun
->script()->owner
= NULL
;
1909 JS_ASSERT(fun
->nargs
== fun
->script()->bindings
.countArgs());
1910 js_CallNewScriptHook(cx
, fun
->script(), fun
);
1916 #else /* !JS_HAS_XDR */
1918 #define js_XDRFunctionObject NULL
1920 #endif /* !JS_HAS_XDR */
1923 * [[HasInstance]] internal method for Function objects: fetch the .prototype
1924 * property of its 'this' parameter, and walks the prototype chain of v (only
1925 * if v is an object) returning true if .prototype is found.
1928 fun_hasInstance(JSContext
*cx
, JSObject
*obj
, const Value
*v
, JSBool
*bp
)
1930 while (obj
->isFunction()) {
1931 if (!obj
->isBoundFunction())
1933 obj
= obj
->getBoundFunctionTarget();
1936 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1938 if (!obj
->getProperty(cx
, id
, &pval
))
1941 if (pval
.isPrimitive()) {
1943 * Throw a runtime error if instanceof is called on a function that
1944 * has a non-object as its .prototype value.
1946 js_ReportValueError(cx
, JSMSG_BAD_PROTOTYPE
, -1, ObjectValue(*obj
), NULL
);
1950 *bp
= js_IsDelegate(cx
, &pval
.toObject(), *v
);
1955 fun_trace(JSTracer
*trc
, JSObject
*obj
)
1957 /* A newborn function object may have a not yet initialized private slot. */
1958 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
1963 /* obj is a cloned function object, trace the clone-parent, fun. */
1964 MarkObject(trc
, *fun
, "private");
1966 /* The function could be a flat closure with upvar copies in the clone. */
1967 if (fun
->isFlatClosure() && fun
->script()->bindings
.hasUpvars()) {
1968 MarkValueRange(trc
, fun
->script()->bindings
.countUpvars(),
1969 obj
->getFlatClosureUpvars(), "upvars");
1975 MarkString(trc
, ATOM_TO_STRING(fun
->atom
), "atom");
1977 if (fun
->isInterpreted() && fun
->script())
1978 js_TraceScript(trc
, fun
->script());
1982 fun_finalize(JSContext
*cx
, JSObject
*obj
)
1984 /* Ignore newborn function objects. */
1985 JSFunction
*fun
= obj
->getFunctionPrivate();
1989 /* Cloned function objects may be flat closures with upvars to free. */
1991 if (fun
->isFlatClosure() && fun
->script()->bindings
.hasUpvars())
1992 cx
->free((void *) obj
->getFlatClosureUpvars());
1997 * Null-check fun->script() because the parser sets interpreted very early.
1999 if (fun
->isInterpreted() && fun
->script())
2000 js_DestroyScriptFromGC(cx
, fun
->script());
2004 * Reserve two slots in all function objects for XPConnect. Note that this
2005 * does not bloat every instance, only those on which reserved slots are set,
2006 * and those on which ad-hoc properties are defined.
2008 JS_PUBLIC_DATA(Class
) js_FunctionClass
= {
2010 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
2011 JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS
) |
2012 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Function
),
2013 PropertyStub
, /* addProperty */
2014 PropertyStub
, /* delProperty */
2015 PropertyStub
, /* getProperty */
2016 StrictPropertyStub
, /* setProperty */
2018 (JSResolveOp
)fun_resolve
,
2021 NULL
, /* reserved0 */
2022 NULL
, /* checkAccess */
2024 NULL
, /* construct */
2025 js_XDRFunctionObject
,
2027 JS_CLASS_TRACE(fun_trace
)
2031 fun_toStringHelper(JSContext
*cx
, JSObject
*obj
, uintN indent
)
2033 if (!obj
->isFunction()) {
2034 if (obj
->isFunctionProxy())
2035 return JSProxy::fun_toString(cx
, obj
, indent
);
2036 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2037 JSMSG_INCOMPATIBLE_PROTO
,
2038 js_Function_str
, js_toString_str
,
2043 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
2048 ToSourceCache::Ptr p
= cx
->compartment
->toSourceCache
.lookup(fun
);
2053 JSString
*str
= JS_DecompileFunction(cx
, fun
, indent
);
2058 cx
->compartment
->toSourceCache
.put(fun
, str
);
2064 fun_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
2066 JS_ASSERT(IsFunctionObject(vp
[0]));
2067 uint32_t indent
= 0;
2069 if (argc
!= 0 && !ValueToECMAUint32(cx
, vp
[2], &indent
))
2072 JSObject
*obj
= ToObject(cx
, &vp
[1]);
2076 JSString
*str
= fun_toStringHelper(cx
, obj
, indent
);
2086 fun_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
2088 JS_ASSERT(IsFunctionObject(vp
[0]));
2090 JSObject
*obj
= ToObject(cx
, &vp
[1]);
2094 JSString
*str
= fun_toStringHelper(cx
, obj
, JS_DONT_PRETTY_PRINT
);
2104 js_fun_call(JSContext
*cx
, uintN argc
, Value
*vp
)
2109 if (!js_IsCallable(fval
)) {
2110 if (JSString
*str
= js_ValueToString(cx
, fval
)) {
2111 JSAutoByteString
bytes(cx
, str
);
2113 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2114 JSMSG_INCOMPATIBLE_PROTO
,
2115 js_Function_str
, js_call_str
,
2122 Value
*argv
= vp
+ 2;
2125 thisv
.setUndefined();
2133 /* Allocate stack space for fval, obj, and the args. */
2134 InvokeArgsGuard args
;
2135 if (!cx
->stack().pushInvokeArgs(cx
, argc
, &args
))
2138 /* Push fval, thisv, and the args. */
2139 args
.callee() = fval
;
2140 args
.thisv() = thisv
;
2141 memcpy(args
.argv(), argv
, argc
* sizeof *argv
);
2143 bool ok
= Invoke(cx
, args
, 0);
2150 js_fun_apply(JSContext
*cx
, uintN argc
, Value
*vp
)
2154 if (!js_IsCallable(fval
)) {
2155 if (JSString
*str
= js_ValueToString(cx
, fval
)) {
2156 JSAutoByteString
bytes(cx
, str
);
2158 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2159 JSMSG_INCOMPATIBLE_PROTO
,
2160 js_Function_str
, js_apply_str
,
2168 if (argc
< 2 || vp
[3].isNullOrUndefined())
2169 return js_fun_call(cx
, (argc
> 0) ? 1 : 0, vp
);
2171 /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
2174 if (!vp
[3].isObject()) {
2175 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_APPLY_ARGS
, js_apply_str
);
2180 * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
2181 * original version of ES5).
2183 JSObject
*aobj
= &vp
[3].toObject();
2185 if (!js_GetLengthProperty(cx
, aobj
, &length
))
2191 uintN n
= uintN(JS_MIN(length
, JS_ARGS_LENGTH_MAX
));
2193 InvokeArgsGuard args
;
2194 if (!cx
->stack().pushInvokeArgs(cx
, n
, &args
))
2197 /* Push fval, obj, and aobj's elements as args. */
2198 args
.callee() = fval
;
2199 args
.thisv() = vp
[2];
2202 if (!GetElements(cx
, aobj
, n
, args
.argv()))
2206 if (!Invoke(cx
, args
, 0))
2215 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
);
2220 JSObject::initBoundFunction(JSContext
*cx
, const Value
&thisArg
,
2221 const Value
*args
, uintN argslen
)
2223 JS_ASSERT(isFunction());
2225 flags
|= JSObject::BOUND_FUNCTION
;
2226 getSlotRef(JSSLOT_BOUND_FUNCTION_THIS
) = thisArg
;
2227 getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT
).setPrivateUint32(argslen
);
2229 /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
2230 EmptyShape
*empty
= EmptyShape::create(cx
, clasp
);
2234 empty
->slotSpan
+= argslen
;
2237 if (!ensureInstanceReservedSlots(cx
, argslen
))
2240 JS_ASSERT(numSlots() >= argslen
+ FUN_CLASS_RESERVED_SLOTS
);
2241 memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS
, args
, argslen
* sizeof(Value
));
2247 JSObject::getBoundFunctionTarget() const
2249 JS_ASSERT(isFunction());
2250 JS_ASSERT(isBoundFunction());
2252 /* Bound functions abuse |parent| to store their target function. */
2256 inline const js::Value
&
2257 JSObject::getBoundFunctionThis() const
2259 JS_ASSERT(isFunction());
2260 JS_ASSERT(isBoundFunction());
2262 return getSlot(JSSLOT_BOUND_FUNCTION_THIS
);
2265 inline const js::Value
*
2266 JSObject::getBoundFunctionArguments(uintN
&argslen
) const
2268 JS_ASSERT(isFunction());
2269 JS_ASSERT(isBoundFunction());
2271 argslen
= getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT
).toPrivateUint32();
2272 JS_ASSERT_IF(argslen
> 0, numSlots() >= argslen
);
2274 return getSlots() + FUN_CLASS_RESERVED_SLOTS
;
2279 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
2281 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
)
2283 JSObject
*obj
= &vp
[0].toObject();
2284 JS_ASSERT(obj
->isFunction());
2285 JS_ASSERT(obj
->isBoundFunction());
2289 bool constructing
= IsConstructing(vp
);
2291 /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
2293 const Value
*boundArgs
= obj
->getBoundFunctionArguments(argslen
);
2295 if (argc
+ argslen
> JS_ARGS_LENGTH_MAX
) {
2296 js_ReportAllocationOverflow(cx
);
2300 /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
2301 JSObject
*target
= obj
->getBoundFunctionTarget();
2303 /* 15.3.4.5.1 step 2. */
2304 const Value
&boundThis
= obj
->getBoundFunctionThis();
2306 InvokeArgsGuard args
;
2307 if (!cx
->stack().pushInvokeArgs(cx
, argc
+ argslen
, &args
))
2310 /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
2311 memcpy(args
.argv(), boundArgs
, argslen
* sizeof(Value
));
2312 memcpy(args
.argv() + argslen
, vp
+ 2, argc
* sizeof(Value
));
2314 /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
2315 args
.callee().setObject(*target
);
2318 args
.thisv() = boundThis
;
2320 if (constructing
? !InvokeConstructor(cx
, args
) : !Invoke(cx
, args
, 0))
2331 fun_bind(JSContext
*cx
, uintN argc
, Value
*vp
)
2334 Value
&thisv
= vp
[1];
2337 if (!js_IsCallable(thisv
)) {
2338 if (JSString
*str
= js_ValueToString(cx
, thisv
)) {
2339 JSAutoByteString
bytes(cx
, str
);
2341 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2342 JSMSG_INCOMPATIBLE_PROTO
,
2343 js_Function_str
, "bind", bytes
.ptr());
2349 JSObject
*target
= &thisv
.toObject();
2361 if (target
->isFunction()) {
2362 uintN nargs
= target
->getFunctionPrivate()->nargs
;
2363 if (nargs
> argslen
)
2364 length
= nargs
- argslen
;
2367 /* Step 4-6, 10-11. */
2368 JSAtom
*name
= target
->isFunction() ? target
->getFunctionPrivate()->atom
: NULL
;
2370 /* NB: Bound functions abuse |parent| to store their target. */
2372 js_NewFunction(cx
, NULL
, CallOrConstructBoundFunction
, length
,
2373 JSFUN_CONSTRUCTOR
, target
, name
);
2378 Value thisArg
= argc
>= 1 ? vp
[2] : UndefinedValue();
2379 if (!funobj
->initBoundFunction(cx
, thisArg
, args
, argslen
))
2382 /* Steps 17, 19-21 are handled by fun_resolve. */
2383 /* Step 18 is the default for new functions. */
2386 vp
->setObject(*funobj
);
2390 static JSFunctionSpec function_methods
[] = {
2392 JS_FN(js_toSource_str
, fun_toSource
, 0,0),
2394 JS_FN(js_toString_str
, fun_toString
, 0,0),
2395 JS_FN(js_apply_str
, js_fun_apply
, 2,0),
2396 JS_FN(js_call_str
, js_fun_call
, 1,0),
2397 JS_FN("bind", fun_bind
, 1,0),
2402 Function(JSContext
*cx
, uintN argc
, Value
*vp
)
2404 JSObject
*obj
= NewFunction(cx
, NULL
);
2408 /* N.B. overwriting callee with return value */
2409 JSObject
*parent
= vp
[0].toObject().getParent();
2410 vp
[0].setObject(*obj
);
2413 * NB: (new Function) is not lexically closed by its caller, it's just an
2414 * anonymous function in the top-level scope that its constructor inhabits.
2415 * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2416 * and so would a call to f from another top-level's script or function.
2418 * In older versions, before call objects, a new Function was adopted by
2419 * its running context's globalObject, which might be different from the
2420 * top-level reachable from scopeChain (in HTML frames, e.g.).
2422 JSFunction
*fun
= js_NewFunction(cx
, obj
, NULL
, 0, JSFUN_LAMBDA
| JSFUN_INTERPRETED
,
2423 parent
, cx
->runtime
->atomState
.anonymousAtom
);
2428 * Function is static and not called directly by other functions in this
2429 * file, therefore it is callable only as a native function by js_Invoke.
2430 * Find the scripted caller, possibly skipping other native frames such as
2431 * are built for Function.prototype.call or .apply activations that invoke
2432 * Function indirectly from a script.
2434 JSStackFrame
*caller
= js_GetScriptedCaller(cx
, NULL
);
2436 const char *filename
;
2437 JSPrincipals
*principals
;
2439 JSObject
*callee
= &JS_CALLEE(cx
, vp
).toObject();
2440 principals
= js_EvalFramePrincipals(cx
, callee
, caller
);
2441 filename
= js_ComputeFilename(cx
, caller
, principals
, &lineno
);
2448 /* Belt-and-braces: check that the caller has access to parent. */
2449 if (!js_CheckPrincipalsAccess(cx
, parent
, principals
,
2450 CLASS_ATOM(cx
, Function
))) {
2455 * CSP check: whether new Function() is allowed at all.
2456 * Report errors via CSP is done in the script security manager.
2457 * js_CheckContentSecurityPolicy is defined in jsobj.cpp
2459 if (!js_CheckContentSecurityPolicy(cx
, parent
)) {
2460 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CSP_BLOCKED_FUNCTION
);
2464 Bindings
bindings(cx
);
2465 AutoBindingsRooter
root(cx
, bindings
);
2467 Value
*argv
= vp
+ 2;
2468 uintN n
= argc
? argc
- 1 : 0;
2470 enum { OK
, BAD
, BAD_FORMAL
} state
;
2473 * Collect the function-argument arguments into one string, separated
2474 * by commas, then make a tokenstream from that string, and scan it to
2475 * get the arguments. We need to throw the full scanner at the
2476 * problem, because the argument string can legitimately contain
2477 * comments and linefeeds. XXX It might be better to concatenate
2478 * everything up into a function definition and pass it to the
2479 * compiler, but doing it this way is less of a delta from the old
2480 * code. See ECMA 15.3.2.1.
2483 size_t args_length
= 0;
2484 for (uintN i
= 0; i
< n
; i
++) {
2485 /* Collect the lengths for all the function-argument arguments. */
2486 JSString
*arg
= js_ValueToString(cx
, argv
[i
]);
2489 argv
[i
].setString(arg
);
2492 * Check for overflow. The < test works because the maximum
2493 * JSString length fits in 2 fewer bits than size_t has.
2495 size_t old_args_length
= args_length
;
2496 args_length
= old_args_length
+ arg
->length();
2497 if (args_length
< old_args_length
) {
2498 js_ReportAllocationOverflow(cx
);
2503 /* Add 1 for each joining comma and check for overflow (two ways). */
2504 size_t old_args_length
= args_length
;
2505 args_length
= old_args_length
+ n
- 1;
2506 if (args_length
< old_args_length
||
2507 args_length
>= ~(size_t)0 / sizeof(jschar
)) {
2508 js_ReportAllocationOverflow(cx
);
2513 * Allocate a string to hold the concatenated arguments, including room
2514 * for a terminating 0. Mark cx->tempPool for later release, to free
2515 * collected_args and its tokenstream in one swoop.
2517 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2519 JS_ARENA_ALLOCATE_CAST(cp
, jschar
*, &cx
->tempPool
,
2520 (args_length
+1) * sizeof(jschar
));
2522 js_ReportOutOfScriptQuota(cx
);
2525 jschar
*collected_args
= cp
;
2528 * Concatenate the arguments into the new string, separated by commas.
2530 for (uintN i
= 0; i
< n
; i
++) {
2531 JSString
*arg
= argv
[i
].toString();
2532 size_t arg_length
= arg
->length();
2533 const jschar
*arg_chars
= arg
->getChars(cx
);
2535 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2538 (void) js_strncpy(cp
, arg_chars
, arg_length
);
2541 /* Add separating comma or terminating 0. */
2542 *cp
++ = (i
+ 1 < n
) ? ',' : 0;
2545 /* Initialize a tokenstream that reads from the given string. */
2547 if (!ts
.init(collected_args
, args_length
, filename
, lineno
, cx
->findVersion())) {
2548 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2552 /* The argument string may be empty or contain no tokens. */
2553 TokenKind tt
= ts
.getToken();
2554 if (tt
!= TOK_EOF
) {
2557 * Check that it's a name. This also implicitly guards against
2558 * TOK_ERROR, which was already reported.
2564 * Get the atom corresponding to the name from the token
2565 * stream; we're assured at this point that it's a valid
2568 JSAtom
*atom
= ts
.currentToken().t_atom
;
2570 /* Check for a duplicate parameter name. */
2571 if (bindings
.hasBinding(cx
, atom
)) {
2572 JSAutoByteString name
;
2573 if (!js_AtomToPrintableString(cx
, atom
, &name
)) {
2577 if (!ReportCompileErrorNumber(cx
, &ts
, NULL
,
2578 JSREPORT_WARNING
| JSREPORT_STRICT
,
2579 JSMSG_DUPLICATE_FORMAL
, name
.ptr())) {
2586 if (!bindings
.addArgument(cx
, atom
, &dummy
)) {
2592 * Get the next token. Stop on end of stream. Otherwise
2593 * insist on a comma, get another name, and iterate.
2598 if (tt
!= TOK_COMMA
)
2606 if (state
== BAD_FORMAL
&& !ts
.isError()) {
2608 * Report "malformed formal parameter" iff no illegal char or
2609 * similar scanner error was already reported.
2611 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2615 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2622 str
= js_ValueToString(cx
, argv
[argc
- 1]);
2625 argv
[argc
- 1].setString(str
);
2627 str
= cx
->runtime
->emptyString
;
2630 size_t length
= str
->length();
2631 const jschar
*chars
= str
->getChars(cx
);
2635 return Compiler::compileFunctionBody(cx
, fun
, principals
, &bindings
,
2636 chars
, length
, filename
, lineno
, cx
->findVersion());
2642 IsBuiltinFunctionConstructor(JSFunction
*fun
)
2644 return fun
->maybeNative() == Function
;
2648 LookupInterpretedFunctionPrototype(JSContext
*cx
, JSObject
*funobj
)
2651 JSFunction
*fun
= funobj
->getFunctionPrivate();
2652 JS_ASSERT(fun
->isInterpreted());
2653 JS_ASSERT(!fun
->isFunctionPrototype());
2654 JS_ASSERT(!funobj
->isBoundFunction());
2657 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
2658 const Shape
*shape
= funobj
->nativeLookup(id
);
2660 if (!ResolveInterpretedFunctionPrototype(cx
, funobj
))
2662 shape
= funobj
->nativeLookup(id
);
2664 JS_ASSERT(!shape
->configurable());
2665 JS_ASSERT(shape
->isDataDescriptor());
2666 JS_ASSERT(shape
->hasSlot());
2667 JS_ASSERT(!shape
->isMethod());
2674 ThrowTypeError(JSContext
*cx
, uintN argc
, Value
*vp
)
2676 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
2677 JSMSG_THROW_TYPE_ERROR
);
2682 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
)
2684 JSObject
*proto
= js_InitClass(cx
, obj
, NULL
, &js_FunctionClass
, Function
, 1,
2685 NULL
, function_methods
, NULL
, NULL
);
2689 JSFunction
*fun
= js_NewFunction(cx
, proto
, NULL
, 0, JSFUN_INTERPRETED
, obj
, NULL
);
2692 fun
->flags
|= JSFUN_PROTOTYPE
;
2694 JSScript
*script
= JSScript::NewScript(cx
, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT
);
2697 script
->noScriptRval
= true;
2698 script
->code
[0] = JSOP_STOP
;
2699 script
->code
[1] = SRC_NULL
;
2700 #ifdef CHECK_SCRIPT_OWNER
2701 script
->owner
= NULL
;
2703 fun
->u
.i
.script
= script
;
2705 if (obj
->isGlobal()) {
2706 /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
2707 JSObject
*throwTypeError
=
2708 js_NewFunction(cx
, NULL
, reinterpret_cast<Native
>(ThrowTypeError
), 0,
2710 if (!throwTypeError
)
2713 JS_ALWAYS_TRUE(js_SetReservedSlot(cx
, obj
, JSRESERVED_GLOBAL_THROWTYPEERROR
,
2714 ObjectValue(*throwTypeError
)));
2721 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, Native native
, uintN nargs
,
2722 uintN flags
, JSObject
*parent
, JSAtom
*atom
)
2727 JS_ASSERT(funobj
->isFunction());
2728 funobj
->setParent(parent
);
2730 funobj
= NewFunction(cx
, parent
);
2734 JS_ASSERT(!funobj
->getPrivate());
2735 fun
= (JSFunction
*) funobj
;
2737 /* Initialize all function members. */
2738 fun
->nargs
= uint16(nargs
);
2739 fun
->flags
= flags
& (JSFUN_FLAGS_MASK
| JSFUN_KINDMASK
| JSFUN_TRCINFO
);
2740 if ((flags
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
) {
2742 JS_ASSERT(nargs
== 0);
2743 fun
->u
.i
.skipmin
= 0;
2744 fun
->u
.i
.wrapper
= false;
2745 fun
->u
.i
.script
= NULL
;
2747 fun
->u
.n
.clasp
= NULL
;
2748 if (flags
& JSFUN_TRCINFO
) {
2750 JSNativeTraceInfo
*trcinfo
=
2751 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo
*, native
);
2752 fun
->u
.n
.native
= (js::Native
) trcinfo
->native
;
2753 fun
->u
.n
.trcinfo
= trcinfo
;
2755 fun
->u
.n
.trcinfo
= NULL
;
2758 fun
->u
.n
.native
= native
;
2759 fun
->u
.n
.trcinfo
= NULL
;
2761 JS_ASSERT(fun
->u
.n
.native
);
2765 /* Set private to self to indicate non-cloned fully initialized function. */
2766 FUN_OBJECT(fun
)->setPrivate(fun
);
2770 JSObject
* JS_FASTCALL
2771 js_CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
,
2778 if (cx
->compartment
== fun
->compartment()) {
2780 * The cloned function object does not need the extra JSFunction members
2781 * beyond JSObject as it points to fun via the private slot.
2783 clone
= NewNativeClassInstance(cx
, &js_FunctionClass
, proto
, parent
);
2786 clone
->setPrivate(fun
);
2789 * Across compartments we have to deep copy JSFunction and clone the
2790 * script (for interpreted functions).
2792 clone
= NewFunction(cx
, parent
);
2795 JSFunction
*cfun
= (JSFunction
*) clone
;
2796 cfun
->nargs
= fun
->nargs
;
2797 cfun
->flags
= fun
->flags
;
2798 cfun
->u
= fun
->getFunctionPrivate()->u
;
2799 cfun
->atom
= fun
->atom
;
2800 clone
->setPrivate(cfun
);
2801 if (cfun
->isInterpreted()) {
2802 JSScript
*script
= cfun
->u
.i
.script
;
2804 JS_ASSERT(script
->compartment
== fun
->compartment());
2805 JS_ASSERT(script
->compartment
!= cx
->compartment
);
2807 cfun
->u
.i
.script
= js_CloneScript(cx
, script
);
2808 if (!cfun
->u
.i
.script
)
2810 #ifdef CHECK_SCRIPT_OWNER
2811 cfun
->script()->owner
= NULL
;
2813 js_CallNewScriptHook(cx
, cfun
->script(), cfun
);
2820 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CloneFunctionObject
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
, 0,
2821 nanojit::ACCSET_STORE_ANY
)
2825 * Create a new flat closure, but don't initialize the imported upvar
2826 * values. The tracer calls this function and then initializes the upvar
2829 JSObject
* JS_FASTCALL
2830 js_AllocFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
)
2832 JS_ASSERT(fun
->isFlatClosure());
2833 JS_ASSERT(JSScript::isValidOffset(fun
->script()->upvarsOffset
) ==
2834 fun
->script()->bindings
.hasUpvars());
2835 JS_ASSERT_IF(JSScript::isValidOffset(fun
->script()->upvarsOffset
),
2836 fun
->script()->upvars()->length
== fun
->script()->bindings
.countUpvars());
2838 JSObject
*closure
= CloneFunctionObject(cx
, fun
, scopeChain
);
2842 uint32 nslots
= fun
->script()->bindings
.countUpvars();
2846 Value
*upvars
= (Value
*) cx
->malloc(nslots
* sizeof(Value
));
2850 closure
->setFlatClosureUpvars(upvars
);
2854 JS_DEFINE_CALLINFO_3(extern, OBJECT
, js_AllocFlatClosure
,
2855 CONTEXT
, FUNCTION
, OBJECT
, 0, nanojit::ACCSET_STORE_ANY
)
2858 js_NewFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSOp op
, size_t oplen
)
2861 * Flat closures cannot yet be partial, that is, all upvars must be copied,
2862 * or the closure won't be flattened. Therefore they do not need to search
2863 * enclosing scope objects via JSOP_NAME, etc.
2865 * FIXME: bug 545759 proposes to enable partial flat closures. Fixing this
2866 * bug requires a GetScopeChainFast call here, along with JS_REQUIRES_STACK
2867 * annotations on this function's prototype and definition.
2869 VOUCH_DOES_NOT_REQUIRE_STACK();
2870 JSObject
*scopeChain
= &cx
->fp()->scopeChain();
2872 JSObject
*closure
= js_AllocFlatClosure(cx
, fun
, scopeChain
);
2873 if (!closure
|| !fun
->script()->bindings
.hasUpvars())
2876 Value
*upvars
= closure
->getFlatClosureUpvars();
2877 uintN level
= fun
->u
.i
.script
->staticLevel
;
2878 JSUpvarArray
*uva
= fun
->script()->upvars();
2880 for (uint32 i
= 0, n
= uva
->length
; i
< n
; i
++)
2881 upvars
[i
] = GetUpvar(cx
, level
, uva
->vector
[i
]);
2887 js_NewDebuggableFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2889 JS_ASSERT(cx
->fp()->fun()->flags
& JSFUN_HEAVYWEIGHT
);
2890 JS_ASSERT(!cx
->fp()->fun()->optimizedClosure());
2891 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
2893 return WrapEscapingClosure(cx
, cx
->fp(), fun
);
2897 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, jsid id
, Native native
,
2898 uintN nargs
, uintN attrs
)
2901 StrictPropertyOp sop
;
2904 if (attrs
& JSFUN_STUB_GSOPS
) {
2906 * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2907 * the defined property's attributes. This allows us to encode another,
2908 * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2911 attrs
&= ~JSFUN_STUB_GSOPS
;
2913 sop
= StrictPropertyStub
;
2920 * Historically, all objects have had a parent member as intrinsic scope
2921 * chain link. We want to move away from this universal parent, but JS
2922 * requires that function objects have something like parent (ES3 and ES5
2923 * call it the [[Scope]] internal property), to bake a particular static
2924 * scope environment into each function object.
2926 * All function objects thus have parent, including all native functions.
2927 * All native functions defined by the JS_DefineFunction* APIs are created
2928 * via the call below to js_NewFunction, which passes obj as the parent
2929 * parameter, and so binds fun's parent to obj using JSObject::setParent,
2930 * under js_NewFunction (in JSObject::init, called from NewObject -- see
2933 * But JSObject::setParent sets the DELEGATE object flag on its receiver,
2934 * to mark the object as a proto or parent of another object. Such objects
2935 * may intervene in property lookups and scope chain searches, so require
2936 * special handling when caching lookup and search results (since such
2937 * intervening objects can in general grow shadowing properties later).
2939 * Thus using setParent prematurely flags certain objects, notably class
2940 * prototypes, so that defining native methods on them, where the method's
2941 * name (e.g., toString) is already bound on Object.prototype, triggers
2942 * shadowingShapeChange events and gratuitous shape regeneration.
2944 * To fix this longstanding bug, we set check whether obj is already a
2945 * delegate, and if not, then if js_NewFunction flagged obj as a delegate,
2946 * we clear the flag.
2948 * We thus rely on the fact that native functions (including indirect eval)
2949 * do not use the property cache or equivalent JIT techniques that require
2950 * this bit to be set on their parent-linked scope chain objects.
2952 * Note: we keep API compatibility by setting parent to obj for all native
2953 * function objects, even if obj->getGlobal() would suffice. This should be
2954 * revisited when parent is narrowed to exist only for function objects and
2955 * possibly a few prehistoric scope objects (e.g. event targets).
2957 * FIXME: bug 611190.
2959 bool wasDelegate
= obj
->isDelegate();
2961 fun
= js_NewFunction(cx
, NULL
, native
, nargs
,
2962 attrs
& (JSFUN_FLAGS_MASK
| JSFUN_TRCINFO
),
2964 JSID_IS_ATOM(id
) ? JSID_TO_ATOM(id
) : NULL
);
2968 if (!wasDelegate
&& obj
->isDelegate())
2969 obj
->clearDelegate();
2971 if (!obj
->defineProperty(cx
, id
, ObjectValue(*fun
), gop
, sop
, attrs
& ~JSFUN_FLAGS_MASK
))
2976 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2977 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2981 js_ValueToFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
2984 if (!IsFunctionObject(*vp
, &funobj
)) {
2985 js_ReportIsNotFunction(cx
, vp
, flags
);
2988 return GET_FUNCTION_PRIVATE(cx
, funobj
);
2992 js_ValueToFunctionObject(JSContext
*cx
, Value
*vp
, uintN flags
)
2995 if (!IsFunctionObject(*vp
, &funobj
)) {
2996 js_ReportIsNotFunction(cx
, vp
, flags
);
3004 js_ValueToCallableObject(JSContext
*cx
, Value
*vp
, uintN flags
)
3006 if (vp
->isObject()) {
3007 JSObject
*callable
= &vp
->toObject();
3008 if (callable
->isCallable())
3012 js_ReportIsNotFunction(cx
, vp
, flags
);
3017 js_ReportIsNotFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
3019 const char *name
= NULL
, *source
= NULL
;
3020 AutoValueRooter
tvr(cx
);
3021 uintN error
= (flags
& JSV2F_CONSTRUCT
) ? JSMSG_NOT_CONSTRUCTOR
: JSMSG_NOT_FUNCTION
;
3025 * We try to the print the code that produced vp if vp is a value in the
3026 * most recent interpreted stack frame. Note that additional values, not
3027 * directly produced by the script, may have been pushed onto the frame's
3028 * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
3029 * the depth simulated by ReconstructPCStack.
3031 * Conversely, values may have been popped from the stack in preparation
3032 * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from
3033 * the top of the simulated stack to js_ReportValueError3, we do bounds
3034 * checking using the minimum of both the simulated and actual stack depth.
3036 ptrdiff_t spindex
= 0;
3038 FrameRegsIter
i(cx
);
3039 while (!i
.done() && !i
.pc())
3043 uintN depth
= js_ReconstructStackDepth(cx
, i
.fp()->script(), i
.pc());
3044 Value
*simsp
= i
.fp()->base() + depth
;
3045 if (i
.fp()->base() <= vp
&& vp
< Min(simsp
, i
.sp()))
3046 spindex
= vp
- simsp
;
3050 spindex
= ((flags
& JSV2F_SEARCH_STACK
) ? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK
);
3052 js_ReportValueError3(cx
, error
, spindex
, *vp
, NULL
, name
, source
);