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.
48 #include "jsutil.h" /* Added by JSIFY */
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"
97 JSObject::getThrowTypeError() const
99 return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR
).toObject();
103 js_GetArgsValue(JSContext
*cx
, JSStackFrame
*fp
, Value
*vp
)
107 if (fp
->hasOverriddenArgs()) {
108 JS_ASSERT(fp
->hasCallObj());
109 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
110 return fp
->callObj().getProperty(cx
, id
, vp
);
112 argsobj
= js_GetArgsObject(cx
, fp
);
115 vp
->setObject(*argsobj
);
120 js_GetArgsProperty(JSContext
*cx
, JSStackFrame
*fp
, jsid id
, Value
*vp
)
122 JS_ASSERT(fp
->isFunctionFrame());
124 if (fp
->hasOverriddenArgs()) {
125 JS_ASSERT(fp
->hasCallObj());
127 jsid argumentsid
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
129 if (!fp
->callObj().getProperty(cx
, argumentsid
, &v
))
133 if (v
.isPrimitive()) {
134 obj
= js_ValueToNonNullObject(cx
, v
);
140 return obj
->getProperty(cx
, id
, vp
);
144 if (JSID_IS_INT(id
)) {
145 uint32 arg
= uint32(JSID_TO_INT(id
));
146 JSObject
*argsobj
= fp
->maybeArgsObj();
147 if (arg
< fp
->numActualArgs()) {
149 if (argsobj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
150 return argsobj
->getProperty(cx
, id
, vp
);
152 *vp
= fp
->canonicalActualArg(arg
);
155 * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
156 * storage between the formal parameter and arguments[k] for all
157 * fp->argc <= k && k < fp->fun->nargs. For example, in
159 * function f(x) { x = 42; return arguments[0]; }
162 * the call to f should return undefined, not 42. If fp->argsobj
163 * is null at this point, as it would be in the example, return
167 return argsobj
->getProperty(cx
, id
, vp
);
169 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
170 JSObject
*argsobj
= fp
->maybeArgsObj();
171 if (argsobj
&& argsobj
->isArgsLengthOverridden())
172 return argsobj
->getProperty(cx
, id
, vp
);
173 vp
->setInt32(fp
->numActualArgs());
179 NewArguments(JSContext
*cx
, JSObject
*parent
, uint32 argc
, JSObject
&callee
)
182 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
185 JSObject
*argsobj
= js_NewGCObject(cx
);
189 ArgumentsData
*data
= (ArgumentsData
*)
190 cx
->malloc(offsetof(ArgumentsData
, slots
) + argc
* sizeof(Value
));
193 SetValueRangeToUndefined(data
->slots
, argc
);
195 /* Can't fail from here on, so initialize everything in argsobj. */
196 argsobj
->init(callee
.getFunctionPrivate()->inStrictMode()
197 ? &StrictArgumentsClass
198 : &js_ArgumentsClass
,
199 proto
, parent
, NULL
, cx
);
201 argsobj
->setMap(cx
->runtime
->emptyArgumentsShape
);
203 argsobj
->setArgsLength(argc
);
204 argsobj
->setArgsData(data
);
205 data
->callee
.setObject(callee
);
214 PutArg(Value
*dst
) : dst(dst
) {}
216 void operator()(uintN
, Value
*src
) {
217 if (!dst
->isMagic(JS_ARGS_HOLE
))
226 js_GetArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
229 * We must be in a function activation; the function must be lightweight
230 * or else fp must have a variable object.
232 JS_ASSERT_IF(fp
->fun()->isHeavyweight(), fp
->hasCallObj());
234 while (fp
->isEvalOrDebuggerFrame())
237 /* Create an arguments object for fp only if it lacks one. */
238 if (fp
->hasArgsObj())
239 return &fp
->argsObj();
241 /* Compute the arguments object's parent slot from fp's scope chain. */
242 JSObject
*global
= fp
->scopeChain().getGlobal();
243 JSObject
*argsobj
= NewArguments(cx
, global
, fp
->numActualArgs(), fp
->callee());
248 * Strict mode functions have arguments objects that copy the initial
249 * actual parameter values. It is the caller's responsibility to get the
250 * arguments object before any parameters are modified! (The emitter
251 * ensures this by synthesizing an arguments access at the start of any
252 * strict mode function that contains an assignment to a parameter, or
253 * that calls eval.) Non-strict mode arguments use the frame pointer to
254 * retrieve up-to-date parameter values.
256 if (argsobj
->isStrictArguments())
257 fp
->forEachCanonicalActualArg(PutArg(argsobj
->getArgsData()->slots
));
259 argsobj
->setPrivate(fp
);
261 fp
->setArgsObj(*argsobj
);
266 js_PutArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
268 JSObject
&argsobj
= fp
->argsObj();
269 if (argsobj
.isNormalArguments()) {
270 JS_ASSERT(argsobj
.getPrivate() == fp
);
271 fp
->forEachCanonicalActualArg(PutArg(argsobj
.getArgsData()->slots
));
272 argsobj
.setPrivate(NULL
);
274 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
= js_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
.nvars
= fun
->u
.i
.nvars
;
376 wfun
->u
.i
.nupvars
= fun
->u
.i
.nupvars
;
377 wfun
->u
.i
.skipmin
= fun
->u
.i
.skipmin
;
378 wfun
->u
.i
.wrapper
= true;
379 wfun
->u
.i
.script
= NULL
;
380 wfun
->u
.i
.names
= fun
->u
.i
.names
;
381 wfun
->atom
= fun
->atom
;
383 JSScript
*script
= fun
->u
.i
.script
;
384 jssrcnote
*snbase
= script
->notes();
385 jssrcnote
*sn
= snbase
;
386 while (!SN_IS_TERMINATOR(sn
))
388 uintN nsrcnotes
= (sn
- snbase
) + 1;
390 /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
391 JSScript
*wscript
= js_NewScript(cx
, script
->length
, nsrcnotes
,
392 script
->atomMap
.length
,
393 (script
->objectsOffset
!= 0)
394 ? script
->objects()->length
397 (script
->regexpsOffset
!= 0)
398 ? script
->regexps()->length
400 (script
->trynotesOffset
!= 0)
401 ? script
->trynotes()->length
403 (script
->constOffset
!= 0)
404 ? script
->consts()->length
406 (script
->globalsOffset
!= 0)
407 ? script
->globals()->length
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 (script
->objectsOffset
!= 0) {
419 memcpy(wscript
->objects()->vector
, script
->objects()->vector
,
420 wscript
->objects()->length
* sizeof(JSObject
*));
422 if (script
->regexpsOffset
!= 0) {
423 memcpy(wscript
->regexps()->vector
, script
->regexps()->vector
,
424 wscript
->regexps()->length
* sizeof(JSObject
*));
426 if (script
->trynotesOffset
!= 0) {
427 memcpy(wscript
->trynotes()->vector
, script
->trynotes()->vector
,
428 wscript
->trynotes()->length
* sizeof(JSTryNote
));
430 if (script
->globalsOffset
!= 0) {
431 memcpy(wscript
->globals()->vector
, script
->globals()->vector
,
432 wscript
->globals()->length
* sizeof(GlobalSlotArray::Entry
));
435 if (wfun
->u
.i
.nupvars
!= 0) {
436 JS_ASSERT(wfun
->u
.i
.nupvars
== wscript
->upvars()->length
);
437 memcpy(wscript
->upvars()->vector
, script
->upvars()->vector
,
438 wfun
->u
.i
.nupvars
* sizeof(uint32
));
441 jsbytecode
*pc
= wscript
->code
;
442 while (*pc
!= JSOP_STOP
) {
443 /* FIXME should copy JSOP_TRAP? */
444 JSOp op
= js_GetOpcode(cx
, wscript
, pc
);
445 const JSCodeSpec
*cs
= &js_CodeSpec
[op
];
446 ptrdiff_t oplen
= cs
->length
;
448 oplen
= js_GetVariableBytecodeLength(pc
);
451 * Rewrite JSOP_{GET,CALL}FCSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
452 * case where fun is an escaping flat closure. This works because the
453 * UPVAR and FCSLOT ops by design have the same format: an upvar index
457 case JSOP_GETUPVAR
: *pc
= JSOP_GETUPVAR_DBG
; break;
458 case JSOP_CALLUPVAR
: *pc
= JSOP_CALLUPVAR_DBG
; break;
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 wscript
->noScriptRval
= script
->noScriptRval
;
474 wscript
->savedCallerFun
= script
->savedCallerFun
;
475 wscript
->hasSharps
= script
->hasSharps
;
476 wscript
->strictModeCode
= script
->strictModeCode
;
477 wscript
->setVersion(script
->getVersion());
478 wscript
->nfixed
= script
->nfixed
;
479 wscript
->filename
= script
->filename
;
480 wscript
->lineno
= script
->lineno
;
481 wscript
->nslots
= script
->nslots
;
482 wscript
->staticLevel
= script
->staticLevel
;
483 wscript
->principals
= script
->principals
;
484 if (wscript
->principals
)
485 JSPRINCIPALS_HOLD(cx
, wscript
->principals
);
486 #ifdef CHECK_SCRIPT_OWNER
487 wscript
->owner
= script
->owner
;
490 /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
491 FUN_SET_KIND(wfun
, JSFUN_INTERPRETED
);
492 wfun
->u
.i
.script
= wscript
;
497 ArgGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
501 if (!InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
504 if (JSID_IS_INT(id
)) {
506 * arg can exceed the number of arguments if a script changed the
507 * prototype to point to another Arguments object with a bigger argc.
509 uintN arg
= uintN(JSID_TO_INT(id
));
510 if (arg
< obj
->getArgsInitialLength()) {
511 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
513 JS_ASSERT(fp
->numActualArgs() == obj
->getArgsInitialLength());
514 *vp
= fp
->canonicalActualArg(arg
);
516 const Value
&v
= obj
->getArgsElement(arg
);
517 if (!v
.isMagic(JS_ARGS_HOLE
))
521 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
522 if (!obj
->isArgsLengthOverridden())
523 vp
->setInt32(obj
->getArgsInitialLength());
525 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
));
526 const Value
&v
= obj
->getArgsCallee();
527 if (!v
.isMagic(JS_ARGS_HOLE
)) {
529 * If this function or one in it needs upvars that reach above it
530 * in the scope chain, it must not be a null closure (it could be a
531 * flat closure, or an unoptimized closure -- the latter itself not
532 * necessarily heavyweight). Rather than wrap here, we simply throw
533 * to reduce code size and tell debugger users the truth instead of
534 * passing off a fibbing wrapper.
536 if (GET_FUNCTION_PRIVATE(cx
, &v
.toObject())->needsWrapper()) {
537 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
538 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
548 ArgSetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
551 // To be able to set a property here on trace, we would have to make
552 // sure any updates also get written back to the trace native stack.
553 // For simplicity, we just leave trace, since this is presumably not
554 // a common operation.
555 if (JS_ON_TRACE(cx
)) {
561 if (!InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
564 if (JSID_IS_INT(id
)) {
565 uintN arg
= uintN(JSID_TO_INT(id
));
566 if (arg
< obj
->getArgsInitialLength()) {
567 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
569 fp
->canonicalActualArg(arg
) = *vp
;
574 JS_ASSERT(JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
) ||
575 JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
));
579 * For simplicity we use delete/set to replace the property with one
580 * backed by the default Object getter and setter. Note that we rely on
581 * args_delProperty to clear the corresponding reserved slot so the GC can
584 AutoValueRooter
tvr(cx
);
585 return js_DeleteProperty(cx
, obj
, id
, tvr
.addr()) &&
586 js_SetProperty(cx
, obj
, id
, vp
);
590 args_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
593 JS_ASSERT(obj
->isNormalArguments());
597 uintN attrs
= JSPROP_SHARED
;
598 if (JSID_IS_INT(id
)) {
599 uint32 arg
= uint32(JSID_TO_INT(id
));
600 attrs
= JSPROP_ENUMERATE
| JSPROP_SHARED
;
601 if (arg
< obj
->getArgsInitialLength() && !obj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
603 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
604 if (!obj
->isArgsLengthOverridden())
606 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
)) {
607 if (!obj
->getArgsCallee().isMagic(JS_ARGS_HOLE
))
612 Value tmp
= UndefinedValue();
613 if (!js_DefineProperty(cx
, obj
, id
, &tmp
, ArgGetter
, ArgSetter
, attrs
))
621 args_enumerate(JSContext
*cx
, JSObject
*obj
)
623 JS_ASSERT(obj
->isNormalArguments());
626 * Trigger reflection in args_resolve using a series of js_LookupProperty
629 int argc
= int(obj
->getArgsInitialLength());
630 for (int i
= -2; i
!= argc
; i
++) {
632 ? ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)
634 ? ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
)
639 if (!js_LookupProperty(cx
, obj
, id
, &pobj
, &prop
))
642 /* prop is null when the property was deleted. */
644 pobj
->dropProperty(cx
, 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()) &&
702 js_SetProperty(cx
, obj
, id
, vp
);
706 strictargs_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
, JSObject
**objp
)
708 JS_ASSERT(obj
->isStrictArguments());
712 uintN attrs
= JSPROP_SHARED
;
713 if (JSID_IS_INT(id
)) {
714 uint32 arg
= uint32(JSID_TO_INT(id
));
715 attrs
= JSPROP_SHARED
| JSPROP_ENUMERATE
;
716 if (arg
< obj
->getArgsInitialLength() && !obj
->getArgsElement(arg
).isMagic(JS_ARGS_HOLE
))
718 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
719 if (!obj
->isArgsLengthOverridden())
721 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.calleeAtom
)) {
722 Value tmp
= UndefinedValue();
723 PropertyOp throwTypeError
= CastAsPropertyOp(obj
->getThrowTypeError());
724 uintN attrs
= JSPROP_PERMANENT
| JSPROP_GETTER
| JSPROP_SETTER
| JSPROP_SHARED
;
725 if (!js_DefineProperty(cx
, obj
, id
, &tmp
, throwTypeError
, throwTypeError
, attrs
))
730 } else if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.callerAtom
)) {
732 * Strict mode arguments objects have an immutable poison-pill caller
733 * property that throws a TypeError on getting or setting.
735 PropertyOp throwTypeError
= CastAsPropertyOp(obj
->getThrowTypeError());
736 Value tmp
= UndefinedValue();
737 if (!js_DefineProperty(cx
, obj
, id
, &tmp
, throwTypeError
, throwTypeError
,
738 JSPROP_PERMANENT
| JSPROP_GETTER
| JSPROP_SETTER
| JSPROP_SHARED
)) {
747 Value tmp
= UndefinedValue();
748 if (!js_DefineProperty(cx
, obj
, id
, &tmp
, StrictArgGetter
, StrictArgSetter
, attrs
))
756 strictargs_enumerate(JSContext
*cx
, JSObject
*obj
)
758 JS_ASSERT(obj
->isStrictArguments());
761 * Trigger reflection in strictargs_resolve using a series of
762 * js_LookupProperty calls. Beware deleted properties!
768 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
), &pobj
, &prop
))
771 pobj
->dropProperty(cx
, prop
);
774 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
), &pobj
, &prop
))
777 pobj
->dropProperty(cx
, prop
);
780 if (!js_LookupProperty(cx
, obj
, ATOM_TO_JSID(cx
->runtime
->atomState
.callerAtom
), &pobj
, &prop
))
783 pobj
->dropProperty(cx
, prop
);
785 for (uint32 i
= 0, argc
= obj
->getArgsInitialLength(); i
< argc
; i
++) {
786 if (!js_LookupProperty(cx
, obj
, INT_TO_JSID(i
), &pobj
, &prop
))
789 pobj
->dropProperty(cx
, prop
);
798 args_finalize(JSContext
*cx
, JSObject
*obj
)
800 cx
->free((void *) obj
->getArgsData());
804 * If a generator's arguments or call object escapes, and the generator frame
805 * is not executing, the generator object needs to be marked because it is not
806 * otherwise reachable. An executing generator is rooted by its invocation. To
807 * distinguish the two cases (which imply different access paths to the
808 * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
809 * set on the JSStackFrame kept in the generator object's JSGenerator.
812 MaybeMarkGenerator(JSTracer
*trc
, JSObject
*obj
)
814 #if JS_HAS_GENERATORS
815 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
816 if (fp
&& fp
->isFloatingGenerator()) {
817 JSObject
*genobj
= js_FloatingFrameToGenerator(fp
)->obj
;
818 MarkObject(trc
, *genobj
, "generator object");
824 args_trace(JSTracer
*trc
, JSObject
*obj
)
826 JS_ASSERT(obj
->isArguments());
827 if (obj
->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE
) {
828 JS_ASSERT(!obj
->isStrictArguments());
832 ArgumentsData
*data
= obj
->getArgsData();
833 if (data
->callee
.isObject())
834 MarkObject(trc
, data
->callee
.toObject(), js_callee_str
);
835 MarkValueRange(trc
, obj
->getArgsInitialLength(), data
->slots
, js_arguments_str
);
837 MaybeMarkGenerator(trc
, obj
);
841 * The Arguments classes aren't initialized via js_InitClass, because arguments
842 * objects have the initial value of Object.prototype as their [[Prototype]].
843 * However, Object.prototype.toString.call(arguments) === "[object Arguments]"
844 * per ES5 (although not ES3), so the class name is "Arguments" rather than
847 * The JSClass functions below collaborate to lazily reflect and synchronize
848 * actual argument values, argument count, and callee function object stored
849 * in a JSStackFrame with their corresponding property values in the frame's
852 Class js_ArgumentsClass
= {
854 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
855 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
856 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
857 PropertyStub
, /* addProperty */
859 PropertyStub
, /* getProperty */
860 PropertyStub
, /* setProperty */
862 (JSResolveOp
) args_resolve
,
864 args_finalize
, /* finalize */
865 NULL
, /* reserved0 */
866 NULL
, /* checkAccess */
868 NULL
, /* construct */
869 NULL
, /* xdrObject */
870 NULL
, /* hasInstance */
871 JS_CLASS_TRACE(args_trace
)
877 * Strict mode arguments is significantly less magical than non-strict mode
878 * arguments, so it is represented by a different class while sharing some
881 Class StrictArgumentsClass
= {
883 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
884 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS
) |
885 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
886 PropertyStub
, /* addProperty */
888 PropertyStub
, /* getProperty */
889 PropertyStub
, /* setProperty */
890 strictargs_enumerate
,
891 reinterpret_cast<JSResolveOp
>(strictargs_resolve
),
893 args_finalize
, /* finalize */
894 NULL
, /* reserved0 */
895 NULL
, /* checkAccess */
897 NULL
, /* construct */
898 NULL
, /* xdrObject */
899 NULL
, /* hasInstance */
900 JS_CLASS_TRACE(args_trace
)
906 * A Declarative Environment object stores its active JSStackFrame pointer in
907 * its private slot, just as Call and Arguments objects do.
909 Class js_DeclEnvClass
= {
911 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
912 PropertyStub
, /* addProperty */
913 PropertyStub
, /* delProperty */
914 PropertyStub
, /* getProperty */
915 PropertyStub
, /* setProperty */
922 CheckForEscapingClosure(JSContext
*cx
, JSObject
*obj
, Value
*vp
)
924 JS_ASSERT(obj
->isCall() || obj
->getClass() == &js_DeclEnvClass
);
926 const Value
&v
= *vp
;
929 if (IsFunctionObject(v
, &funobj
)) {
930 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
933 * Any escaping null or flat closure that reaches above itself or
934 * contains nested functions that reach above it must be wrapped.
935 * We can wrap only when this Call or Declarative Environment obj
936 * still has an active stack frame associated with it.
938 if (fun
->needsWrapper()) {
941 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
943 JSObject
*wrapper
= WrapEscapingClosure(cx
, fp
, fun
);
946 vp
->setObject(*wrapper
);
950 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
951 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
959 CalleeGetter(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
961 return CheckForEscapingClosure(cx
, obj
, vp
);
965 NewCallObject(JSContext
*cx
, JSFunction
*fun
, JSObject
&scopeChain
, JSObject
&callee
)
967 JSObject
*callobj
= js_NewGCObject(cx
);
971 callobj
->init(&js_CallClass
, NULL
, &scopeChain
, NULL
, cx
);
972 callobj
->setMap(fun
->u
.i
.names
);
974 /* This must come after callobj->lastProp has been set. */
975 if (!callobj
->ensureInstanceReservedSlots(cx
, fun
->countArgsAndVars()))
979 for (Shape::Range r
= callobj
->lastProp
; !r
.empty(); r
.popFront()) {
980 const Shape
&s
= r
.front();
981 if (s
.slot
!= SHAPE_INVALID_SLOT
) {
982 JS_ASSERT(s
.slot
+ 1 == callobj
->slotSpan());
988 callobj
->setCallObjCallee(callee
);
992 static inline JSObject
*
993 NewDeclEnvObject(JSContext
*cx
, JSStackFrame
*fp
)
995 JSObject
*envobj
= js_NewGCObject(cx
);
999 envobj
->init(&js_DeclEnvClass
, NULL
, &fp
->scopeChain(), fp
, cx
);
1000 envobj
->setMap(cx
->runtime
->emptyDeclEnvShape
);
1005 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1007 /* Create a call object for fp only if it lacks one. */
1008 JS_ASSERT(fp
->isFunctionFrame());
1009 if (fp
->hasCallObj())
1010 return &fp
->callObj();
1013 /* A call object should be a frame's outermost scope chain element. */
1014 Class
*clasp
= fp
->scopeChain().getClass();
1015 if (clasp
== &js_WithClass
|| clasp
== &js_BlockClass
)
1016 JS_ASSERT(fp
->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx
, fp
));
1017 else if (clasp
== &js_CallClass
)
1018 JS_ASSERT(fp
->scopeChain().getPrivate() != fp
);
1022 * Create the call object, using the frame's enclosing scope as its
1023 * parent, and link the call to its stack frame. For a named function
1024 * expression Call's parent points to an environment object holding
1027 JSAtom
*lambdaName
=
1028 (fp
->fun()->flags
& JSFUN_LAMBDA
) ? fp
->fun()->atom
: NULL
;
1030 JSObject
*envobj
= NewDeclEnvObject(cx
, fp
);
1034 /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
1035 fp
->setScopeChainNoCallObj(*envobj
);
1036 if (!js_DefineNativeProperty(cx
, &fp
->scopeChain(), ATOM_TO_JSID(lambdaName
),
1037 ObjectValue(fp
->callee()),
1039 JSPROP_PERMANENT
| JSPROP_READONLY
,
1045 JSObject
*callobj
= NewCallObject(cx
, fp
->fun(), fp
->scopeChain(), fp
->callee());
1049 callobj
->setPrivate(fp
);
1050 JS_ASSERT(fp
->fun() == fp
->callee().getFunctionPrivate());
1053 * Push callobj on the top of the scope chain, and make it the
1056 fp
->setScopeChainAndCallObj(*callobj
);
1060 JSObject
* JS_FASTCALL
1061 js_CreateCallObjectOnTrace(JSContext
*cx
, JSFunction
*fun
, JSObject
*callee
, JSObject
*scopeChain
)
1063 JS_ASSERT(!js_IsNamedLambda(fun
));
1064 JS_ASSERT(scopeChain
);
1065 return NewCallObject(cx
, fun
, *scopeChain
, *callee
);
1068 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CreateCallObjectOnTrace
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
,
1069 0, nanojit::ACCSET_STORE_ANY
)
1072 CopyValuesToCallObject(JSObject
&callobj
, uintN nargs
, Value
*argv
, uintN nvars
, Value
*slots
)
1074 /* Copy however many args fit into fslots. */
1075 uintN first
= JSSLOT_PRIVATE
+ JSObject::CALL_RESERVED_SLOTS
+ 1;
1076 JS_ASSERT(first
<= JS_INITIAL_NSLOTS
);
1078 Value
*vp
= &callobj
.fslots
[first
];
1079 uintN len
= Min(nargs
, uintN(JS_INITIAL_NSLOTS
) - first
);
1081 memcpy(vp
, argv
, len
* sizeof(Value
));
1086 /* Copy any remaining args into dslots. */
1087 vp
= callobj
.dslots
;
1088 memcpy(vp
, argv
+ len
, nargs
* sizeof(Value
));
1091 /* Copy however many vars fit into any remaining fslots. */
1093 len
= JS_MIN(nvars
, JS_INITIAL_NSLOTS
- first
);
1094 memcpy(vp
, slots
, len
* sizeof(Value
));
1097 vp
= callobj
.dslots
;
1100 /* Copy any remaining vars into dslots. */
1101 memcpy(vp
, slots
, nvars
* sizeof(Value
));
1105 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1107 JSObject
&callobj
= fp
->callObj();
1109 /* Get the arguments object to snapshot fp's actual argument values. */
1110 if (fp
->hasArgsObj()) {
1111 if (!fp
->hasOverriddenArgs())
1112 callobj
.setCallObjArguments(ObjectValue(fp
->argsObj()));
1113 js_PutArgsObject(cx
, fp
);
1116 JSFunction
*fun
= fp
->fun();
1117 JS_ASSERT(fun
== callobj
.getCallObjCalleeFunction());
1118 uintN n
= fun
->countArgsAndVars();
1121 * Since for a call object all fixed slots happen to be taken, we can copy
1122 * arguments and variables straight into JSObject.dslots.
1124 JS_STATIC_ASSERT(JS_INITIAL_NSLOTS
- JSSLOT_PRIVATE
==
1125 1 + JSObject::CALL_RESERVED_SLOTS
);
1127 JS_ASSERT(JSFunction::FIRST_FREE_SLOT
+ n
<= callobj
.numSlots());
1129 uint32 nargs
= fun
->nargs
;
1130 uint32 nvars
= fun
->u
.i
.nvars
;
1133 JS_STATIC_ASSERT(JS_INITIAL_NSLOTS
== JSSLOT_PRIVATE
+ JSObject::CALL_RESERVED_SLOTS
+ 1);
1134 JSScript
*script
= fun
->u
.i
.script
;
1135 memcpy(callobj
.dslots
, fp
->formalArgs(), nargs
* sizeof(Value
));
1136 if (!script
->jit
|| script
->usesEval
) {
1137 memcpy(callobj
.dslots
+ nargs
, fp
->slots(), nvars
* sizeof(Value
));
1138 } else if (script
->jit
) {
1139 for (uint32 i
= 0; i
< script
->jit
->nescaping
; i
++) {
1140 uint32 e
= script
->jit
->escaping
[i
];
1141 callobj
.dslots
[nargs
+ e
] = fp
->slots()[e
];
1145 CopyValuesToCallObject(callobj
, nargs
, fp
->formalArgs(), nvars
, fp
->slots());
1149 /* Clear private pointers to fp, which is about to go away (js_Invoke). */
1150 if (js_IsNamedLambda(fun
)) {
1151 JSObject
*env
= callobj
.getParent();
1153 JS_ASSERT(env
->getClass() == &js_DeclEnvClass
);
1154 JS_ASSERT(env
->getPrivate() == fp
);
1155 env
->setPrivate(NULL
);
1158 callobj
.setPrivate(NULL
);
1162 js_PutCallObjectOnTrace(JSContext
*cx
, JSObject
*callobj
, uint32 nargs
, Value
*argv
,
1163 uint32 nvars
, Value
*slots
)
1165 JS_ASSERT(callobj
->isCall());
1166 JS_ASSERT(!callobj
->getPrivate());
1168 uintN n
= nargs
+ nvars
;
1170 CopyValuesToCallObject(*callobj
, nargs
, argv
, nvars
, slots
);
1175 JS_DEFINE_CALLINFO_6(extern, BOOL
, js_PutCallObjectOnTrace
, CONTEXT
, OBJECT
, UINT32
, VALUEPTR
,
1176 UINT32
, VALUEPTR
, 0, nanojit::ACCSET_STORE_ANY
)
1178 enum JSCallPropertyKind
{
1186 CallPropertyOp(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
,
1187 JSCallPropertyKind kind
, JSBool setter
= false)
1189 JS_ASSERT(obj
->isCall());
1192 if (kind
!= JSCPK_ARGUMENTS
) {
1193 JS_ASSERT((int16
) JSID_TO_INT(id
) == JSID_TO_INT(id
));
1194 i
= (uint16
) JSID_TO_INT(id
);
1198 if (kind
== JSCPK_UPVAR
) {
1199 JSObject
&callee
= obj
->getCallObjCallee();
1202 JSFunction
*callee_fun
= (JSFunction
*) callee
.getPrivate();
1203 JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun
));
1204 JS_ASSERT(i
< callee_fun
->u
.i
.nupvars
);
1207 array
= callee
.getFlatClosureUpvars();
1209 JSFunction
*fun
= obj
->getCallObjCalleeFunction();
1210 JS_ASSERT_IF(kind
== JSCPK_ARG
, i
< fun
->nargs
);
1211 JS_ASSERT_IF(kind
== JSCPK_VAR
, i
< fun
->u
.i
.nvars
);
1213 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
1215 if (kind
== JSCPK_ARGUMENTS
) {
1218 fp
->setOverriddenArgs();
1219 obj
->setCallObjArguments(*vp
);
1221 if (fp
&& !fp
->hasOverriddenArgs()) {
1224 argsobj
= js_GetArgsObject(cx
, fp
);
1227 vp
->setObject(*argsobj
);
1229 *vp
= obj
->getCallObjArguments();
1236 if (kind
== JSCPK_VAR
)
1239 JS_ASSERT(kind
== JSCPK_ARG
);
1241 const uintN first
= JSSLOT_PRIVATE
+ JSObject::CALL_RESERVED_SLOTS
+ 1;
1242 JS_ASSERT(first
== JSSLOT_FREE(&js_CallClass
));
1243 JS_ASSERT(first
<= JS_INITIAL_NSLOTS
);
1245 array
= (i
< JS_INITIAL_NSLOTS
- first
) ? obj
->fslots
: obj
->dslots
;
1246 } else if (kind
== JSCPK_ARG
) {
1247 array
= fp
->formalArgs();
1249 JS_ASSERT(kind
== JSCPK_VAR
);
1250 array
= fp
->slots();
1255 GC_POKE(cx
, array
[i
]);
1264 GetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1266 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARGUMENTS
);
1270 SetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1272 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARGUMENTS
, true);
1276 js_GetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1278 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARG
);
1282 SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1284 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARG
, true);
1288 GetFlatUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1290 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_UPVAR
);
1294 SetFlatUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1296 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_UPVAR
, true);
1300 js_GetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1302 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
);
1306 js_GetCallVarChecked(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1308 if (!CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
))
1311 return CheckForEscapingClosure(cx
, obj
, vp
);
1315 SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1317 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
, true);
1322 js_SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1324 Value argcopy
= ValueArgToConstRef(arg
);
1325 return CallPropertyOp(cx
, obj
, slotid
, &argcopy
, JSCPK_ARG
, true);
1327 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallArg
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1328 nanojit::ACCSET_STORE_ANY
)
1331 js_SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid slotid
, ValueArgType arg
)
1333 Value argcopy
= ValueArgToConstRef(arg
);
1334 return CallPropertyOp(cx
, obj
, slotid
, &argcopy
, JSCPK_VAR
, true);
1336 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallVar
, CONTEXT
, OBJECT
, JSID
, VALUE
, 0,
1337 nanojit::ACCSET_STORE_ANY
)
1341 call_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1344 JS_ASSERT(obj
->isCall());
1345 JS_ASSERT(!obj
->getProto());
1347 if (!JSID_IS_ATOM(id
))
1351 JSFunction
*fun
= obj
->getCallObjCalleeFunction();
1352 JS_ASSERT(fun
->lookupLocal(cx
, JSID_TO_ATOM(id
), NULL
) == JSLOCAL_NONE
);
1356 * Resolve arguments so that we never store a particular Call object's
1357 * arguments object reference in a Call prototype's |arguments| slot.
1359 if (JSID_IS_ATOM(id
, cx
->runtime
->atomState
.argumentsAtom
)) {
1360 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(),
1361 GetCallArguments
, SetCallArguments
,
1362 JSPROP_PERMANENT
| JSPROP_SHARED
,
1363 0, 0, NULL
, JSDNP_DONT_PURGE
)) {
1370 /* Control flow reaches here only if id was not resolved. */
1375 call_trace(JSTracer
*trc
, JSObject
*obj
)
1377 JS_ASSERT(obj
->isCall());
1378 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
1381 * FIXME: Hide copies of stack values rooted by fp from the Cycle
1382 * Collector, which currently lacks a non-stub Unlink implementation
1383 * for JS objects (including Call objects), so is unable to collect
1384 * cycles involving Call objects whose frames are active without this
1387 uintN first
= JSSLOT_PRIVATE
+ JSObject::CALL_RESERVED_SLOTS
+ 1;
1388 JS_ASSERT(first
<= JS_INITIAL_NSLOTS
);
1390 uintN count
= fp
->fun()->countArgsAndVars();
1391 uintN fixed
= JS_MIN(count
, JS_INITIAL_NSLOTS
- first
);
1393 SetValueRangeToUndefined(&obj
->fslots
[first
], fixed
);
1394 SetValueRangeToUndefined(obj
->dslots
, count
- fixed
);
1397 MaybeMarkGenerator(trc
, obj
);
1400 JS_PUBLIC_DATA(Class
) js_CallClass
= {
1402 JSCLASS_HAS_PRIVATE
|
1403 JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS
) |
1404 JSCLASS_NEW_RESOLVE
| JSCLASS_IS_ANONYMOUS
| JSCLASS_MARK_IS_TRACE
,
1405 PropertyStub
, /* addProperty */
1406 PropertyStub
, /* delProperty */
1407 PropertyStub
, /* getProperty */
1408 PropertyStub
, /* setProperty */
1410 (JSResolveOp
)call_resolve
,
1412 NULL
, /* finalize */
1413 NULL
, /* reserved0 */
1414 NULL
, /* checkAccess */
1416 NULL
, /* construct */
1417 NULL
, /* xdrObject */
1418 NULL
, /* hasInstance */
1419 JS_CLASS_TRACE(call_trace
)
1423 JSStackFrame::getValidCalleeObject(JSContext
*cx
, Value
*vp
)
1425 if (!isFunctionFrame()) {
1430 JSFunction
*fun
= this->fun();
1433 * See the equivalent condition in ArgGetter for the 'callee' id case, but
1434 * note that here we do not want to throw, since this escape can happen via
1435 * a foo.caller reference alone, without any debugger or indirect eval. And
1436 * alas, it seems foo.caller is still used on the Web.
1438 if (fun
->needsWrapper()) {
1439 JSObject
*wrapper
= WrapEscapingClosure(cx
, this, fun
);
1442 vp
->setObject(*wrapper
);
1446 JSObject
&funobj
= callee();
1447 vp
->setObject(funobj
);
1450 * Check for an escape attempt by a joined function object, which must go
1451 * through the frame's |this| object's method read barrier for the method
1452 * atom by which it was uniquely associated with a property.
1454 const Value
&thisv
= functionThis();
1455 if (thisv
.isObject()) {
1456 JS_ASSERT(funobj
.getFunctionPrivate() == fun
);
1458 if (&fun
->compiledFunObj() == &funobj
&& fun
->methodAtom()) {
1459 JSObject
*thisp
= &thisv
.toObject();
1460 JS_ASSERT(thisp
->canHaveMethodBarrier());
1462 if (thisp
->hasMethodBarrier()) {
1463 const Shape
*shape
= thisp
->nativeLookup(ATOM_TO_JSID(fun
->methodAtom()));
1466 * The method property might have been deleted while the method
1467 * barrier flag stuck, so we must lookup and test here.
1469 * Two cases follow: the method barrier was not crossed yet, so
1470 * we cross it here; the method barrier *was* crossed, in which
1471 * case we must fetch and validate the cloned (unjoined) funobj
1472 * in the method property's slot.
1474 * In either case we must allow for the method property to have
1475 * been replaced, or its value to have been overwritten.
1478 if (shape
->isMethod() && &shape
->methodObject() == &funobj
) {
1479 if (!thisp
->methodReadBarrier(cx
, *shape
, vp
))
1481 calleeValue().setObject(vp
->toObject());
1484 if (shape
->hasSlot()) {
1485 Value v
= thisp
->getSlot(shape
->slot
);
1488 if (IsFunctionObject(v
, &clone
) &&
1489 GET_FUNCTION_PRIVATE(cx
, clone
) == fun
&&
1490 clone
->hasMethodObj(*thisp
)) {
1491 JS_ASSERT(clone
!= &funobj
);
1493 calleeValue().setObject(*clone
);
1500 * If control flows here, we can't find an already-existing
1501 * clone (or force to exist a fresh clone) created via thisp's
1502 * method read barrier, so we must clone fun and store it in
1503 * fp's callee to avoid re-cloning upon repeated foo.caller
1504 * access. It seems that there are no longer any properties
1507 JSObject
*newfunobj
= CloneFunctionObject(cx
, fun
, fun
->getParent());
1510 newfunobj
->setMethodObj(*thisp
);
1511 calleeValue().setObject(*newfunobj
);
1520 /* Generic function tinyids. */
1522 FUN_ARGUMENTS
= -1, /* predefined arguments local variable */
1523 FUN_LENGTH
= -2, /* number of actual args, arity if inactive */
1524 FUN_ARITY
= -3, /* number of formal parameters; desired argc */
1525 FUN_NAME
= -4, /* function name, "" if anonymous */
1526 FUN_CALLER
= -5 /* Function.prototype.caller, backward compat */
1530 fun_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
1532 if (!JSID_IS_INT(id
))
1535 jsint slot
= JSID_TO_INT(id
);
1538 * Loop because getter and setter can be delegated from another class,
1539 * but loop only for FUN_LENGTH because we must pretend that f.length
1540 * is in each function instance f, per ECMA-262, instead of only in the
1541 * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1542 * to make it appear so).
1544 * This code couples tightly to the attributes for lazyFunctionDataProps[]
1545 * and poisonPillProps[] initializers below, and to js_SetProperty and
1546 * js_HasOwnProperty.
1548 * It's important to allow delegating objects, even though they inherit
1549 * this getter (fun_getProperty), to override arguments, arity, caller,
1550 * and name. If we didn't return early for slot != FUN_LENGTH, we would
1551 * clobber *vp with the native property value, instead of letting script
1552 * override that value in delegating objects.
1554 * Note how that clobbering is what simulates JSPROP_READONLY for all of
1555 * the non-standard properties when the directly addressed object (obj)
1556 * is a function object (i.e., when this loop does not iterate).
1559 while (!(fun
= (JSFunction
*)
1560 GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
))) {
1561 if (slot
!= FUN_LENGTH
)
1563 obj
= obj
->getProto();
1568 /* Find fun's top-most activation record. */
1570 for (fp
= js_GetTopStackFrame(cx
);
1571 fp
&& (fp
->maybeFun() != fun
|| fp
->isEvalOrDebuggerFrame());
1578 /* Warn if strict about f.arguments or equivalent unqualified uses. */
1579 if (!JS_ReportErrorFlagsAndNumber(cx
,
1580 JSREPORT_WARNING
| JSREPORT_STRICT
,
1581 js_GetErrorMessage
, NULL
,
1582 JSMSG_DEPRECATED_USAGE
,
1583 js_arguments_str
)) {
1587 if (!js_GetArgsValue(cx
, fp
, vp
))
1596 vp
->setInt32(fun
->nargs
);
1600 vp
->setString(fun
->atom
? ATOM_TO_STRING(fun
->atom
)
1601 : cx
->runtime
->emptyString
);
1606 if (fp
&& fp
->prev() && !fp
->prev()->getValidCalleeObject(cx
, vp
))
1609 if (vp
->isObject()) {
1610 JSObject
&caller
= vp
->toObject();
1612 /* Censor the caller if it is from another compartment. */
1613 if (caller
.getCompartment(cx
) != cx
->compartment
) {
1615 } else if (caller
.isFunction() && caller
.getFunctionPrivate()->inStrictMode()) {
1616 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
1617 JSMSG_CALLER_IS_STRICT
);
1624 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1625 if (fp
&& fp
->isFunctionFrame() && uint16(slot
) < fp
->numFormalArgs())
1626 *vp
= fp
->formalArg(slot
);
1635 struct LazyFunctionDataProp
{
1641 struct PoisonPillProp
{
1646 /* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
1648 const LazyFunctionDataProp lazyFunctionDataProps
[] = {
1649 {ATOM_OFFSET(arity
), FUN_ARITY
, JSPROP_PERMANENT
},
1650 {ATOM_OFFSET(name
), FUN_NAME
, JSPROP_PERMANENT
},
1653 /* Properties censored into [[ThrowTypeError]] in strict mode. */
1654 const PoisonPillProp poisonPillProps
[] = {
1655 {ATOM_OFFSET(arguments
), FUN_ARGUMENTS
},
1656 {ATOM_OFFSET(caller
), FUN_CALLER
},
1662 fun_enumerate(JSContext
*cx
, JSObject
*obj
)
1664 JS_ASSERT(obj
->isFunction());
1669 if (!obj
->getFunctionPrivate()->isBound()) {
1670 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1671 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1675 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
);
1676 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1679 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1680 const LazyFunctionDataProp
&lfp
= lazyFunctionDataProps
[i
];
1681 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, lfp
.atomOffset
));
1682 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1686 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(poisonPillProps
); i
++) {
1687 const PoisonPillProp
&p
= poisonPillProps
[i
];
1688 id
= ATOM_TO_JSID(OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
));
1689 if (!obj
->hasProperty(cx
, id
, &found
, JSRESOLVE_QUALIFIED
))
1697 fun_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
1700 if (!JSID_IS_ATOM(id
))
1703 JSFunction
*fun
= obj
->getFunctionPrivate();
1706 * No need to reflect fun.prototype in 'fun.prototype = ... '. Assert that
1707 * fun is not a compiler-created function object, which must never leak to
1708 * script or embedding code and then be mutated.
1710 if ((flags
& JSRESOLVE_ASSIGNING
) && !JSID_IS_ATOM(id
, cx
->runtime
->atomState
.lengthAtom
)) {
1711 JS_ASSERT(!IsInternalFunctionObject(obj
));
1716 * Ok, check whether id is 'prototype' and bootstrap the function object's
1717 * prototype property.
1719 JSAtom
*atom
= cx
->runtime
->atomState
.classPrototypeAtom
;
1720 if (id
== ATOM_TO_JSID(atom
)) {
1721 JS_ASSERT(!IsInternalFunctionObject(obj
));
1724 * Beware of the wacky case of a user function named Object -- trying
1725 * to find a prototype for that will recur back here _ad perniciem_.
1727 if (fun
->atom
== CLASS_ATOM(cx
, Object
))
1730 /* ES5 15.3.4.5: bound functions don't have a prototype property. */
1735 * Make the prototype object an instance of Object with the same parent
1736 * as the function object itself.
1738 JSObject
*parent
= obj
->getParent();
1740 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
1742 proto
= NewNativeClassInstance(cx
, &js_ObjectClass
, proto
, parent
);
1747 * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1748 * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1749 * native "system" constructors such as Object or Function. So lazily
1750 * set the former here in fun_resolve, but eagerly define the latter
1751 * in js_InitClass, with the right attributes.
1753 if (!js_SetClassPrototype(cx
, obj
, proto
, JSPROP_PERMANENT
))
1760 atom
= cx
->runtime
->atomState
.lengthAtom
;
1761 if (id
== ATOM_TO_JSID(atom
)) {
1762 JS_ASSERT(!IsInternalFunctionObject(obj
));
1763 if (!js_DefineNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
), Int32Value(fun
->nargs
),
1764 PropertyStub
, PropertyStub
,
1765 JSPROP_PERMANENT
| JSPROP_READONLY
, 0, 0, NULL
)) {
1772 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(lazyFunctionDataProps
); i
++) {
1773 const LazyFunctionDataProp
*lfp
= &lazyFunctionDataProps
[i
];
1775 atom
= OFFSET_TO_ATOM(cx
->runtime
, lfp
->atomOffset
);
1776 if (id
== ATOM_TO_JSID(atom
)) {
1777 JS_ASSERT(!IsInternalFunctionObject(obj
));
1779 if (!js_DefineNativeProperty(cx
, obj
,
1780 ATOM_TO_JSID(atom
), 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 atom
= OFFSET_TO_ATOM(cx
->runtime
, p
.atomOffset
);
1795 if (id
== ATOM_TO_JSID(atom
)) {
1796 JS_ASSERT(!IsInternalFunctionObject(obj
));
1798 PropertyOp getter
, setter
;
1799 uintN attrs
= JSPROP_PERMANENT
;
1800 if (fun
->inStrictMode() || fun
->isBound()) {
1801 JSObject
*throwTypeError
= obj
->getThrowTypeError();
1803 getter
= CastAsPropertyOp(throwTypeError
);
1804 setter
= CastAsPropertyOp(throwTypeError
);
1805 attrs
|= JSPROP_GETTER
| JSPROP_SETTER
;
1807 getter
= fun_getProperty
;
1808 setter
= PropertyStub
;
1811 if (!js_DefineNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
), UndefinedValue(),
1813 attrs
, Shape::HAS_SHORTID
,
1827 /* XXX store parent and proto, if defined */
1829 js_XDRFunctionObject(JSXDRState
*xdr
, JSObject
**objp
)
1833 uint32 firstword
; /* flag telling whether fun->atom is non-null,
1834 plus for fun->u.i.skipmin, fun->u.i.wrapper,
1835 and 14 bits reserved for future use */
1836 uintN nargs
, nvars
, nupvars
, n
;
1837 uint32 localsword
; /* word for argument and variable counts */
1838 uint32 flagsword
; /* word for fun->u.i.nupvars and fun->flags */
1841 if (xdr
->mode
== JSXDR_ENCODE
) {
1842 fun
= GET_FUNCTION_PRIVATE(cx
, *objp
);
1843 if (!FUN_INTERPRETED(fun
)) {
1844 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1845 JSMSG_NOT_SCRIPTED_FUNCTION
,
1846 JS_GetFunctionName(fun
));
1849 if (fun
->u
.i
.wrapper
) {
1850 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1851 JSMSG_XDR_CLOSURE_WRAPPER
,
1852 JS_GetFunctionName(fun
));
1855 JS_ASSERT((fun
->u
.i
.wrapper
& ~1U) == 0);
1856 firstword
= (fun
->u
.i
.skipmin
<< 2) | (fun
->u
.i
.wrapper
<< 1) | !!fun
->atom
;
1858 nvars
= fun
->u
.i
.nvars
;
1859 nupvars
= fun
->u
.i
.nupvars
;
1860 localsword
= (nargs
<< 16) | nvars
;
1861 flagsword
= (nupvars
<< 16) | fun
->flags
;
1863 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, JSFUN_INTERPRETED
, NULL
, NULL
);
1866 FUN_OBJECT(fun
)->clearParent();
1867 FUN_OBJECT(fun
)->clearProto();
1869 nvars
= nargs
= nupvars
= 0; /* quell GCC uninitialized warning */
1873 AutoObjectRooter
tvr(cx
, FUN_OBJECT(fun
));
1875 if (!JS_XDRUint32(xdr
, &firstword
))
1877 if ((firstword
& 1U) && !js_XDRAtom(xdr
, &fun
->atom
))
1879 if (!JS_XDRUint32(xdr
, &localsword
) ||
1880 !JS_XDRUint32(xdr
, &flagsword
)) {
1884 if (xdr
->mode
== JSXDR_DECODE
) {
1885 nargs
= localsword
>> 16;
1886 nvars
= uint16(localsword
);
1887 JS_ASSERT((flagsword
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
);
1888 nupvars
= flagsword
>> 16;
1889 fun
->flags
= uint16(flagsword
);
1890 fun
->u
.i
.skipmin
= uint16(firstword
>> 2);
1891 fun
->u
.i
.wrapper
= JSPackedBool((firstword
>> 1) & 1);
1894 /* do arguments and local vars */
1895 n
= nargs
+ nvars
+ nupvars
;
1903 JSLocalKind localKind
;
1906 mark
= JS_ARENA_MARK(&xdr
->cx
->tempPool
);
1909 * From this point the control must flow via the label release_mark.
1911 * To xdr the names we prefix the names with a bitmap descriptor and
1912 * then xdr the names as strings. For argument names (indexes below
1913 * nargs) the corresponding bit in the bitmap is unset when the name
1914 * is null. Such null names are not encoded or decoded. For variable
1915 * names (indexes starting from nargs) bitmap's bit is set when the
1916 * name is declared as const, not as ordinary var.
1918 MUST_FLOW_THROUGH("release_mark");
1919 bitmapLength
= JS_HOWMANY(n
, JS_BITS_PER_UINT32
);
1920 JS_ARENA_ALLOCATE_CAST(bitmap
, uint32
*, &xdr
->cx
->tempPool
,
1921 bitmapLength
* sizeof *bitmap
);
1923 js_ReportOutOfScriptQuota(xdr
->cx
);
1927 if (xdr
->mode
== JSXDR_ENCODE
) {
1928 names
= fun
->getLocalNameArray(xdr
->cx
, &xdr
->cx
->tempPool
);
1933 PodZero(bitmap
, bitmapLength
);
1934 for (i
= 0; i
!= n
; ++i
) {
1936 ? JS_LOCAL_NAME_TO_ATOM(names
[i
]) != NULL
1937 : JS_LOCAL_NAME_IS_CONST(names
[i
])) {
1938 bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] |=
1939 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1));
1945 names
= NULL
; /* quell GCC uninitialized warning */
1948 for (i
= 0; i
!= bitmapLength
; ++i
) {
1949 ok
= !!JS_XDRUint32(xdr
, &bitmap
[i
]);
1953 for (i
= 0; i
!= n
; ++i
) {
1955 !(bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] &
1956 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1)))) {
1957 if (xdr
->mode
== JSXDR_DECODE
) {
1958 ok
= !!fun
->addLocal(xdr
->cx
, NULL
, JSLOCAL_ARG
);
1962 JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names
[i
]));
1966 if (xdr
->mode
== JSXDR_ENCODE
)
1967 name
= JS_LOCAL_NAME_TO_ATOM(names
[i
]);
1968 ok
= !!js_XDRAtom(xdr
, &name
);
1971 if (xdr
->mode
== JSXDR_DECODE
) {
1972 localKind
= (i
< nargs
)
1974 : (i
< nargs
+ nvars
)
1975 ? (bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] &
1976 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1))
1980 ok
= !!fun
->addLocal(xdr
->cx
, name
, localKind
);
1987 JS_ARENA_RELEASE(&xdr
->cx
->tempPool
, mark
);
1991 if (xdr
->mode
== JSXDR_DECODE
)
1992 fun
->freezeLocalNames(cx
);
1995 if (!js_XDRScript(xdr
, &fun
->u
.i
.script
, false, NULL
))
1998 if (xdr
->mode
== JSXDR_DECODE
) {
1999 *objp
= FUN_OBJECT(fun
);
2000 if (fun
->u
.i
.script
!= JSScript::emptyScript()) {
2001 #ifdef CHECK_SCRIPT_OWNER
2002 fun
->u
.i
.script
->owner
= NULL
;
2004 js_CallNewScriptHook(cx
, fun
->u
.i
.script
, fun
);
2011 #else /* !JS_HAS_XDR */
2013 #define js_XDRFunctionObject NULL
2015 #endif /* !JS_HAS_XDR */
2018 * [[HasInstance]] internal method for Function objects: fetch the .prototype
2019 * property of its 'this' parameter, and walks the prototype chain of v (only
2020 * if v is an object) returning true if .prototype is found.
2023 fun_hasInstance(JSContext
*cx
, JSObject
*obj
, const Value
*v
, JSBool
*bp
)
2025 while (obj
->isFunction()) {
2026 if (!obj
->getFunctionPrivate()->isBound())
2028 obj
= obj
->getBoundFunctionTarget();
2031 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
2033 if (!obj
->getProperty(cx
, id
, &pval
))
2036 if (pval
.isPrimitive()) {
2038 * Throw a runtime error if instanceof is called on a function that
2039 * has a non-object as its .prototype value.
2041 js_ReportValueError(cx
, JSMSG_BAD_PROTOTYPE
, -1, ObjectValue(*obj
), NULL
);
2045 *bp
= js_IsDelegate(cx
, &pval
.toObject(), *v
);
2050 fun_trace(JSTracer
*trc
, JSObject
*obj
)
2052 /* A newborn function object may have a not yet initialized private slot. */
2053 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
2058 /* obj is a cloned function object, trace the clone-parent, fun. */
2059 MarkObject(trc
, *fun
, "private");
2061 /* The function could be a flat closure with upvar copies in the clone. */
2062 if (FUN_FLAT_CLOSURE(fun
) && fun
->u
.i
.nupvars
)
2063 MarkValueRange(trc
, fun
->u
.i
.nupvars
, obj
->getFlatClosureUpvars(), "upvars");
2068 MarkString(trc
, ATOM_TO_STRING(fun
->atom
), "atom");
2070 if (FUN_INTERPRETED(fun
)) {
2071 if (fun
->u
.i
.script
)
2072 js_TraceScript(trc
, fun
->u
.i
.script
);
2073 for (const Shape
*shape
= fun
->u
.i
.names
; shape
; shape
= shape
->previous())
2079 fun_finalize(JSContext
*cx
, JSObject
*obj
)
2081 /* Ignore newborn function objects. */
2082 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
2086 /* Cloned function objects may be flat closures with upvars to free. */
2088 if (FUN_FLAT_CLOSURE(fun
) && fun
->u
.i
.nupvars
!= 0)
2089 cx
->free((void *) obj
->getFlatClosureUpvars());
2094 * Null-check of u.i.script is required since the parser sets interpreted
2097 if (FUN_INTERPRETED(fun
) && fun
->u
.i
.script
)
2098 js_DestroyScript(cx
, fun
->u
.i
.script
);
2102 JSFunction::sharpSlotBase(JSContext
*cx
)
2104 #if JS_HAS_SHARP_VARS
2105 JSAtom
*name
= js_Atomize(cx
, "#array", 6, 0);
2107 uintN index
= uintN(-1);
2111 lookupLocal(cx
, name
, &index
);
2112 JS_ASSERT(kind
== JSLOCAL_VAR
);
2120 JSFunction::countUpvarSlots() const
2122 JS_ASSERT(FUN_INTERPRETED(this));
2124 return (u
.i
.nupvars
== 0) ? 0 : u
.i
.script
->upvars()->length
;
2128 * Reserve two slots in all function objects for XPConnect. Note that this
2129 * does not bloat every instance, only those on which reserved slots are set,
2130 * and those on which ad-hoc properties are defined.
2132 JS_PUBLIC_DATA(Class
) js_FunctionClass
= {
2134 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
2135 JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS
) |
2136 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Function
),
2137 PropertyStub
, /* addProperty */
2138 PropertyStub
, /* delProperty */
2139 PropertyStub
, /* getProperty */
2140 PropertyStub
, /* setProperty */
2142 (JSResolveOp
)fun_resolve
,
2145 NULL
, /* reserved0 */
2146 NULL
, /* checkAccess */
2148 NULL
, /* construct */
2149 js_XDRFunctionObject
,
2151 JS_CLASS_TRACE(fun_trace
)
2155 fun_toStringHelper(JSContext
*cx
, JSObject
*obj
, uintN indent
)
2157 if (!obj
->isFunction()) {
2158 if (obj
->isFunctionProxy())
2159 return JSProxy::fun_toString(cx
, obj
, indent
);
2160 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2161 JSMSG_INCOMPATIBLE_PROTO
,
2162 js_Function_str
, js_toString_str
,
2167 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
2170 return JS_DecompileFunction(cx
, fun
, indent
);
2174 fun_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
2176 JS_ASSERT(IsFunctionObject(vp
[0]));
2177 uint32_t indent
= 0;
2179 if (argc
!= 0 && !ValueToECMAUint32(cx
, vp
[2], &indent
))
2182 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2186 JSString
*str
= fun_toStringHelper(cx
, obj
, indent
);
2196 fun_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
2198 JS_ASSERT(IsFunctionObject(vp
[0]));
2200 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2204 JSString
*str
= fun_toStringHelper(cx
, obj
, JS_DONT_PRETTY_PRINT
);
2214 js_fun_call(JSContext
*cx
, uintN argc
, Value
*vp
)
2218 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2223 if (!js_IsCallable(fval
)) {
2224 JSString
*str
= js_ValueToString(cx
, fval
);
2226 const char *bytes
= js_GetStringBytes(cx
, str
);
2229 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2230 JSMSG_INCOMPATIBLE_PROTO
,
2231 js_Function_str
, js_call_str
,
2238 Value
*argv
= vp
+ 2;
2240 /* Call fun with its global object as the 'this' param if no args. */
2243 /* Otherwise convert the first arg to 'this' and skip over it. */
2244 if (argv
[0].isObject())
2245 obj
= &argv
[0].toObject();
2246 else if (!js_ValueToObjectOrNull(cx
, argv
[0], &obj
))
2252 /* Allocate stack space for fval, obj, and the args. */
2253 InvokeArgsGuard args
;
2254 if (!cx
->stack().pushInvokeArgs(cx
, argc
, &args
))
2257 /* Push fval, obj, and the args. */
2258 args
.callee() = fval
;
2259 args
.thisv().setObjectOrNull(obj
);
2260 memcpy(args
.argv(), argv
, argc
* sizeof *argv
);
2262 bool ok
= Invoke(cx
, args
, 0);
2269 struct CopyNonHoleArgs
2271 CopyNonHoleArgs(JSObject
*aobj
, Value
*dst
) : aobj(aobj
), dst(dst
) {}
2274 void operator()(uintN argi
, Value
*src
) {
2275 if (aobj
->getArgsElement(argi
).isMagic(JS_ARGS_HOLE
))
2276 dst
->setUndefined();
2287 js_fun_apply(JSContext
*cx
, uintN argc
, Value
*vp
)
2289 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
2295 if (!js_IsCallable(fval
)) {
2296 if (JSString
*str
= js_ValueToString(cx
, fval
)) {
2297 if (const char *bytes
= js_GetStringBytes(cx
, str
)) {
2298 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2299 JSMSG_INCOMPATIBLE_PROTO
,
2300 js_Function_str
, js_apply_str
,
2308 if (argc
< 2 || vp
[3].isNullOrUndefined())
2309 return js_fun_call(cx
, (argc
> 0) ? 1 : 0, vp
);
2312 if (!vp
[3].isObject()) {
2313 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_APPLY_ARGS
, js_apply_str
);
2318 * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
2319 * original version of ES5).
2321 JSObject
*aobj
= vp
[3].toObject().wrappedObject(cx
);
2323 if (aobj
->isArray()) {
2324 length
= aobj
->getArrayLength();
2325 } else if (aobj
->isArguments() && !aobj
->isArgsLengthOverridden()) {
2326 length
= aobj
->getArgsInitialLength();
2328 Value
&lenval
= vp
[0];
2329 if (!aobj
->getProperty(cx
, ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
), &lenval
))
2332 if (lenval
.isInt32()) {
2333 length
= jsuint(lenval
.toInt32()); /* jsuint cast does ToUint32 */
2335 JS_STATIC_ASSERT(sizeof(jsuint
) == sizeof(uint32_t));
2336 if (!ValueToECMAUint32(cx
, lenval
, (uint32_t *)&length
))
2341 /* Convert the first arg to 'this' and skip over it. */
2342 if (vp
[2].isObject())
2343 obj
= &vp
[2].toObject();
2344 else if (!js_ValueToObjectOrNull(cx
, vp
[2], &obj
))
2350 uintN n
= uintN(JS_MIN(length
, JS_ARGS_LENGTH_MAX
));
2352 InvokeArgsGuard args
;
2353 if (!cx
->stack().pushInvokeArgs(cx
, n
, &args
))
2356 /* Push fval, obj, and aobj's elements as args. */
2357 args
.callee() = fval
;
2358 args
.thisv().setObjectOrNull(obj
);
2361 if (aobj
&& aobj
->isArguments() && !aobj
->isArgsLengthOverridden()) {
2363 * Two cases, two loops: note how in the case of an active stack frame
2364 * backing aobj, even though we copy from fp->argv, we still must check
2365 * aobj->getArgsElement(i) for a hole, to handle a delete on the
2366 * corresponding arguments element. See args_delProperty.
2368 JSStackFrame
*fp
= (JSStackFrame
*) aobj
->getPrivate();
2369 Value
*argv
= args
.argv();
2371 JS_ASSERT(fp
->numActualArgs() <= JS_ARGS_LENGTH_MAX
);
2372 fp
->forEachCanonicalActualArg(CopyNonHoleArgs(aobj
, argv
));
2374 for (uintN i
= 0; i
< n
; i
++) {
2375 argv
[i
] = aobj
->getArgsElement(i
);
2376 if (argv
[i
].isMagic(JS_ARGS_HOLE
))
2377 argv
[i
].setUndefined();
2381 Value
*argv
= args
.argv();
2382 for (uintN i
= 0; i
< n
; i
++) {
2383 if (!aobj
->getProperty(cx
, INT_TO_JSID(jsint(i
)), &argv
[i
]))
2389 if (!Invoke(cx
, args
, 0))
2398 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
);
2402 JSFunction::isBound() const
2404 return isNative() && u
.n
.native
== CallOrConstructBoundFunction
;
2408 JSObject::initBoundFunction(JSContext
*cx
, const Value
&thisArg
,
2409 const Value
*args
, uintN argslen
)
2411 JS_ASSERT(isFunction());
2412 JS_ASSERT(getFunctionPrivate()->isBound());
2414 fslots
[JSSLOT_BOUND_FUNCTION_THIS
] = thisArg
;
2415 fslots
[JSSLOT_BOUND_FUNCTION_ARGS_COUNT
].setPrivateUint32(argslen
);
2417 /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
2418 EmptyShape
*empty
= EmptyShape::create(cx
, clasp
);
2422 empty
->slotSpan
+= argslen
;
2425 if (!ensureInstanceReservedSlots(cx
, argslen
))
2429 JS_ASSERT(dslots
[-1].toPrivateUint32() >= argslen
);
2430 memcpy(&dslots
[0], args
, argslen
* sizeof(Value
));
2436 JSObject::getBoundFunctionTarget() const
2438 JS_ASSERT(isFunction());
2439 JS_ASSERT(getFunctionPrivate()->isBound());
2441 /* Bound functions abuse |parent| to store their target function. */
2445 inline const js::Value
&
2446 JSObject::getBoundFunctionThis() const
2448 JS_ASSERT(isFunction());
2449 JS_ASSERT(getFunctionPrivate()->isBound());
2451 return fslots
[JSSLOT_BOUND_FUNCTION_THIS
];
2454 inline const js::Value
*
2455 JSObject::getBoundFunctionArguments(uintN
&argslen
) const
2457 JS_ASSERT(isFunction());
2458 JS_ASSERT(getFunctionPrivate()->isBound());
2460 argslen
= fslots
[JSSLOT_BOUND_FUNCTION_ARGS_COUNT
].toPrivateUint32();
2461 JS_ASSERT_IF(argslen
> 0, dslots
);
2462 JS_ASSERT_IF(argslen
> 0, dslots
[-1].toPrivateUint32() >= argslen
);
2468 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
2470 CallOrConstructBoundFunction(JSContext
*cx
, uintN argc
, Value
*vp
)
2472 JSObject
*obj
= &vp
[0].toObject();
2473 JS_ASSERT(obj
->isFunction());
2474 JS_ASSERT(obj
->getFunctionPrivate()->isBound());
2478 bool constructing
= IsConstructing(vp
);
2480 /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
2482 const Value
*boundArgs
= obj
->getBoundFunctionArguments(argslen
);
2484 if (argc
+ argslen
> JS_ARGS_LENGTH_MAX
) {
2485 js_ReportAllocationOverflow(cx
);
2489 /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
2490 JSObject
*target
= obj
->getBoundFunctionTarget();
2492 /* 15.3.4.5.1 step 2. */
2493 const Value
&boundThis
= obj
->getBoundFunctionThis();
2495 InvokeArgsGuard args
;
2496 if (!cx
->stack().pushInvokeArgs(cx
, argc
+ argslen
, &args
))
2499 /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
2500 memcpy(args
.argv(), boundArgs
, argslen
* sizeof(Value
));
2501 memcpy(args
.argv() + argslen
, vp
+ 2, argc
* sizeof(Value
));
2503 /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
2504 args
.callee().setObject(*target
);
2506 if (!constructing
) {
2508 * FIXME Pass boundThis directly without boxing! This will go away
2509 * very shortly when this-boxing only occurs for non-strict
2510 * functions, callee-side, in bug 514570.
2512 JSObject
*boundThisObj
;
2513 if (boundThis
.isObjectOrNull()) {
2514 boundThisObj
= boundThis
.toObjectOrNull();
2516 if (!js_ValueToObjectOrNull(cx
, boundThis
, &boundThisObj
))
2520 args
.thisv() = ObjectOrNullValue(boundThisObj
);
2523 if (constructing
? !InvokeConstructor(cx
, args
) : !Invoke(cx
, args
, 0))
2532 fun_bind(JSContext
*cx
, uintN argc
, Value
*vp
)
2535 JSObject
*target
= ComputeThisFromVp(cx
, vp
);
2540 if (!target
->wrappedObject(cx
)->isCallable()) {
2541 if (JSString
*str
= js_ValueToString(cx
, vp
[1])) {
2542 if (const char *bytes
= js_GetStringBytes(cx
, str
)) {
2543 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2544 JSMSG_INCOMPATIBLE_PROTO
,
2545 js_Function_str
, "bind", bytes
);
2561 if (target
->isFunction()) {
2562 uintN nargs
= target
->getFunctionPrivate()->nargs
;
2563 if (nargs
> argslen
)
2564 length
= nargs
- argslen
;
2567 /* Step 4-6, 10-11. */
2568 JSAtom
*name
= target
->isFunction() ? target
->getFunctionPrivate()->atom
: NULL
;
2570 /* NB: Bound functions abuse |parent| to store their target. */
2572 js_NewFunction(cx
, NULL
, CallOrConstructBoundFunction
, length
,
2573 JSFUN_CONSTRUCTOR
, target
, name
);
2578 Value thisArg
= argc
>= 1 ? vp
[2] : UndefinedValue();
2579 if (!funobj
->initBoundFunction(cx
, thisArg
, args
, argslen
))
2582 /* Steps 17, 19-21 are handled by fun_resolve. */
2583 /* Step 18 is the default for new functions. */
2586 vp
->setObject(*funobj
);
2592 static JSFunctionSpec function_methods
[] = {
2594 JS_FN(js_toSource_str
, fun_toSource
, 0,0),
2596 JS_FN(js_toString_str
, fun_toString
, 0,0),
2597 JS_FN(js_apply_str
, js_fun_apply
, 2,0),
2598 JS_FN(js_call_str
, js_fun_call
, 1,0),
2599 JS_FN("bind", fun_bind
, 1,0),
2604 Function(JSContext
*cx
, uintN argc
, Value
*vp
)
2606 JSObject
*obj
= NewFunction(cx
, NULL
);
2610 /* N.B. overwriting callee with return value */
2611 JSObject
*parent
= vp
[0].toObject().getParent();
2612 vp
[0].setObject(*obj
);
2615 * NB: (new Function) is not lexically closed by its caller, it's just an
2616 * anonymous function in the top-level scope that its constructor inhabits.
2617 * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2618 * and so would a call to f from another top-level's script or function.
2620 * In older versions, before call objects, a new Function was adopted by
2621 * its running context's globalObject, which might be different from the
2622 * top-level reachable from scopeChain (in HTML frames, e.g.).
2624 JSFunction
*fun
= js_NewFunction(cx
, obj
, NULL
, 0, JSFUN_LAMBDA
| JSFUN_INTERPRETED
,
2625 parent
, cx
->runtime
->atomState
.anonymousAtom
);
2630 * Function is static and not called directly by other functions in this
2631 * file, therefore it is callable only as a native function by js_Invoke.
2632 * Find the scripted caller, possibly skipping other native frames such as
2633 * are built for Function.prototype.call or .apply activations that invoke
2634 * Function indirectly from a script.
2636 JSStackFrame
*caller
= js_GetScriptedCaller(cx
, NULL
);
2638 const char *filename
;
2639 JSPrincipals
*principals
;
2641 JSObject
*callee
= &JS_CALLEE(cx
, vp
).toObject();
2642 principals
= js_EvalFramePrincipals(cx
, callee
, caller
);
2643 filename
= js_ComputeFilename(cx
, caller
, principals
, &lineno
);
2650 /* Belt-and-braces: check that the caller has access to parent. */
2651 if (!js_CheckPrincipalsAccess(cx
, parent
, principals
,
2652 CLASS_ATOM(cx
, Function
))) {
2657 * CSP check: whether new Function() is allowed at all.
2658 * Report errors via CSP is done in the script security manager.
2659 * js_CheckContentSecurityPolicy is defined in jsobj.cpp
2661 if (!js_CheckContentSecurityPolicy(cx
)) {
2662 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CSP_BLOCKED_FUNCTION
);
2666 Value
*argv
= vp
+ 2;
2667 uintN n
= argc
? argc
- 1 : 0;
2669 enum { OK
, BAD
, BAD_FORMAL
} state
;
2672 * Collect the function-argument arguments into one string, separated
2673 * by commas, then make a tokenstream from that string, and scan it to
2674 * get the arguments. We need to throw the full scanner at the
2675 * problem, because the argument string can legitimately contain
2676 * comments and linefeeds. XXX It might be better to concatenate
2677 * everything up into a function definition and pass it to the
2678 * compiler, but doing it this way is less of a delta from the old
2679 * code. See ECMA 15.3.2.1.
2682 size_t args_length
= 0;
2683 for (uintN i
= 0; i
< n
; i
++) {
2684 /* Collect the lengths for all the function-argument arguments. */
2685 JSString
*arg
= js_ValueToString(cx
, argv
[i
]);
2688 argv
[i
].setString(arg
);
2691 * Check for overflow. The < test works because the maximum
2692 * JSString length fits in 2 fewer bits than size_t has.
2694 size_t old_args_length
= args_length
;
2695 args_length
= old_args_length
+ arg
->length();
2696 if (args_length
< old_args_length
) {
2697 js_ReportAllocationOverflow(cx
);
2702 /* Add 1 for each joining comma and check for overflow (two ways). */
2703 size_t old_args_length
= args_length
;
2704 args_length
= old_args_length
+ n
- 1;
2705 if (args_length
< old_args_length
||
2706 args_length
>= ~(size_t)0 / sizeof(jschar
)) {
2707 js_ReportAllocationOverflow(cx
);
2712 * Allocate a string to hold the concatenated arguments, including room
2713 * for a terminating 0. Mark cx->tempPool for later release, to free
2714 * collected_args and its tokenstream in one swoop.
2716 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2718 JS_ARENA_ALLOCATE_CAST(cp
, jschar
*, &cx
->tempPool
,
2719 (args_length
+1) * sizeof(jschar
));
2721 js_ReportOutOfScriptQuota(cx
);
2724 jschar
*collected_args
= cp
;
2727 * Concatenate the arguments into the new string, separated by commas.
2729 for (uintN i
= 0; i
< n
; i
++) {
2730 JSString
*arg
= argv
[i
].toString();
2731 size_t arg_length
= arg
->length();
2732 (void) js_strncpy(cp
, arg
->chars(), arg_length
);
2735 /* Add separating comma or terminating 0. */
2736 *cp
++ = (i
+ 1 < n
) ? ',' : 0;
2739 /* Initialize a tokenstream that reads from the given string. */
2741 if (!ts
.init(cx
->findVersion(), collected_args
, args_length
, NULL
, filename
, lineno
)) {
2742 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2746 /* The argument string may be empty or contain no tokens. */
2747 TokenKind tt
= ts
.getToken();
2748 if (tt
!= TOK_EOF
) {
2751 * Check that it's a name. This also implicitly guards against
2752 * TOK_ERROR, which was already reported.
2758 * Get the atom corresponding to the name from the token
2759 * stream; we're assured at this point that it's a valid
2762 JSAtom
*atom
= ts
.currentToken().t_atom
;
2764 /* Check for a duplicate parameter name. */
2765 if (fun
->lookupLocal(cx
, atom
, NULL
) != JSLOCAL_NONE
) {
2768 name
= js_AtomToPrintableString(cx
, atom
);
2769 if (!name
&& ReportCompileErrorNumber(cx
, &ts
, NULL
,
2770 JSREPORT_WARNING
| JSREPORT_STRICT
,
2771 JSMSG_DUPLICATE_FORMAL
, name
)) {
2775 if (!fun
->addLocal(cx
, atom
, JSLOCAL_ARG
))
2779 * Get the next token. Stop on end of stream. Otherwise
2780 * insist on a comma, get another name, and iterate.
2785 if (tt
!= TOK_COMMA
)
2793 if (state
== BAD_FORMAL
&& !ts
.isError()) {
2795 * Report "malformed formal parameter" iff no illegal char or
2796 * similar scanner error was already reported.
2798 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2802 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2809 str
= js_ValueToString(cx
, argv
[argc
-1]);
2812 argv
[argc
-1].setString(str
);
2814 str
= cx
->runtime
->emptyString
;
2817 return Compiler::compileFunctionBody(cx
, fun
, principals
,
2818 str
->chars(), str
->length(),
2825 ThrowTypeError(JSContext
*cx
, uintN argc
, Value
*vp
)
2827 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, NULL
,
2828 JSMSG_THROW_TYPE_ERROR
);
2835 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
)
2837 JSObject
*proto
= js_InitClass(cx
, obj
, NULL
, &js_FunctionClass
, Function
, 1,
2838 NULL
, function_methods
, NULL
, NULL
);
2842 JSFunction
*fun
= js_NewFunction(cx
, proto
, NULL
, 0, JSFUN_INTERPRETED
, obj
, NULL
);
2845 fun
->u
.i
.script
= JSScript::emptyScript();
2847 if (obj
->getClass()->flags
& JSCLASS_IS_GLOBAL
) {
2848 /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
2849 JSObject
*throwTypeError
=
2850 js_NewFunction(cx
, NULL
, reinterpret_cast<Native
>(ThrowTypeError
), 0,
2852 if (!throwTypeError
)
2855 JS_ALWAYS_TRUE(js_SetReservedSlot(cx
, obj
, JSRESERVED_GLOBAL_THROWTYPEERROR
,
2856 ObjectValue(*throwTypeError
)));
2863 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, Native native
, uintN nargs
,
2864 uintN flags
, JSObject
*parent
, JSAtom
*atom
)
2869 JS_ASSERT(funobj
->isFunction());
2870 funobj
->setParent(parent
);
2872 funobj
= NewFunction(cx
, parent
);
2876 JS_ASSERT(!funobj
->getPrivate());
2877 fun
= (JSFunction
*) funobj
;
2879 /* Initialize all function members. */
2880 fun
->nargs
= uint16(nargs
);
2881 fun
->flags
= flags
& (JSFUN_FLAGS_MASK
| JSFUN_KINDMASK
| JSFUN_TRCINFO
);
2882 if ((flags
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
) {
2884 JS_ASSERT(nargs
== 0);
2886 fun
->u
.i
.nupvars
= 0;
2887 fun
->u
.i
.skipmin
= 0;
2888 fun
->u
.i
.wrapper
= false;
2889 fun
->u
.i
.script
= NULL
;
2890 fun
->u
.i
.names
= cx
->runtime
->emptyCallShape
;
2892 fun
->u
.n
.clasp
= NULL
;
2893 if (flags
& JSFUN_TRCINFO
) {
2895 JSNativeTraceInfo
*trcinfo
=
2896 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo
*, native
);
2897 fun
->u
.n
.native
= (js::Native
) trcinfo
->native
;
2898 fun
->u
.n
.trcinfo
= trcinfo
;
2900 fun
->u
.n
.trcinfo
= NULL
;
2903 fun
->u
.n
.native
= native
;
2904 fun
->u
.n
.trcinfo
= NULL
;
2906 JS_ASSERT(fun
->u
.n
.native
);
2910 /* Set private to self to indicate non-cloned fully initialized function. */
2911 FUN_OBJECT(fun
)->setPrivate(fun
);
2915 JSObject
* JS_FASTCALL
2916 js_CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
,
2923 * The cloned function object does not need the extra JSFunction members
2924 * beyond JSObject as it points to fun via the private slot.
2926 JSObject
*clone
= NewNativeClassInstance(cx
, &js_FunctionClass
, proto
, parent
);
2929 clone
->setPrivate(fun
);
2934 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CloneFunctionObject
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
, 0,
2935 nanojit::ACCSET_STORE_ANY
)
2939 * Create a new flat closure, but don't initialize the imported upvar
2940 * values. The tracer calls this function and then initializes the upvar
2943 JSObject
* JS_FASTCALL
2944 js_AllocFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
)
2946 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
2947 JS_ASSERT((fun
->u
.i
.script
->upvarsOffset
2948 ? fun
->u
.i
.script
->upvars()->length
2949 : 0) == fun
->u
.i
.nupvars
);
2951 JSObject
*closure
= CloneFunctionObject(cx
, fun
, scopeChain
);
2955 uint32 nslots
= fun
->countUpvarSlots();
2959 Value
*upvars
= (Value
*) cx
->malloc(nslots
* sizeof(Value
));
2963 closure
->setFlatClosureUpvars(upvars
);
2967 JS_DEFINE_CALLINFO_3(extern, OBJECT
, js_AllocFlatClosure
,
2968 CONTEXT
, FUNCTION
, OBJECT
, 0, nanojit::ACCSET_STORE_ANY
)
2970 JS_REQUIRES_STACK JSObject
*
2971 js_NewFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2974 * Flat closures can be partial, they may need to search enclosing scope
2975 * objects via JSOP_NAME, etc.
2977 JSObject
*scopeChain
= js_GetScopeChain(cx
, cx
->fp());
2981 JSObject
*closure
= js_AllocFlatClosure(cx
, fun
, scopeChain
);
2982 if (!closure
|| fun
->u
.i
.nupvars
== 0)
2985 Value
*upvars
= closure
->getFlatClosureUpvars();
2986 uintN level
= fun
->u
.i
.script
->staticLevel
;
2987 JSUpvarArray
*uva
= fun
->u
.i
.script
->upvars();
2989 for (uint32 i
= 0, n
= uva
->length
; i
< n
; i
++)
2990 upvars
[i
] = GetUpvar(cx
, level
, uva
->vector
[i
]);
2996 js_NewDebuggableFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2998 JS_ASSERT(cx
->fp()->fun()->flags
& JSFUN_HEAVYWEIGHT
);
2999 JS_ASSERT(!cx
->fp()->fun()->optimizedClosure());
3000 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
3002 return WrapEscapingClosure(cx
, cx
->fp(), fun
);
3006 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
, Native native
,
3007 uintN nargs
, uintN attrs
)
3012 if (attrs
& JSFUN_STUB_GSOPS
) {
3014 * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
3015 * the defined property's attributes. This allows us to encode another,
3016 * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
3019 attrs
&= ~JSFUN_STUB_GSOPS
;
3020 gsop
= PropertyStub
;
3024 fun
= js_NewFunction(cx
, NULL
, native
, nargs
,
3025 attrs
& (JSFUN_FLAGS_MASK
| JSFUN_TRCINFO
),
3029 if (!obj
->defineProperty(cx
, ATOM_TO_JSID(atom
), ObjectValue(*fun
),
3030 gsop
, gsop
, attrs
& ~JSFUN_FLAGS_MASK
)) {
3036 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
3037 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
3041 js_ValueToFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
3044 if (!IsFunctionObject(*vp
, &funobj
)) {
3045 js_ReportIsNotFunction(cx
, vp
, flags
);
3048 return GET_FUNCTION_PRIVATE(cx
, funobj
);
3052 js_ValueToFunctionObject(JSContext
*cx
, Value
*vp
, uintN flags
)
3055 if (!IsFunctionObject(*vp
, &funobj
)) {
3056 js_ReportIsNotFunction(cx
, vp
, flags
);
3064 js_ValueToCallableObject(JSContext
*cx
, Value
*vp
, uintN flags
)
3066 if (vp
->isObject()) {
3067 JSObject
*callable
= &vp
->toObject();
3068 if (callable
->isCallable())
3072 js_ReportIsNotFunction(cx
, vp
, flags
);
3077 js_ReportIsNotFunction(JSContext
*cx
, const Value
*vp
, uintN flags
)
3079 const char *name
= NULL
, *source
= NULL
;
3080 AutoValueRooter
tvr(cx
);
3081 uintN error
= (flags
& JSV2F_CONSTRUCT
) ? JSMSG_NOT_CONSTRUCTOR
: JSMSG_NOT_FUNCTION
;
3085 * We try to the print the code that produced vp if vp is a value in the
3086 * most recent interpreted stack frame. Note that additional values, not
3087 * directly produced by the script, may have been pushed onto the frame's
3088 * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
3089 * the depth simulated by ReconstructPCStack. Since we must pass an offset
3090 * from the top of the simulated stack to js_ReportValueError3, it is
3091 * important to do bounds checking using the simulated, rather than actual,
3094 ptrdiff_t spindex
= 0;
3096 FrameRegsIter
i(cx
);
3097 while (!i
.done() && !i
.pc())
3101 uintN depth
= js_ReconstructStackDepth(cx
, i
.fp()->script(), i
.pc());
3102 Value
*simsp
= i
.fp()->base() + depth
;
3103 JS_ASSERT(simsp
<= i
.sp());
3104 if (i
.fp()->base() <= vp
&& vp
< simsp
)
3105 spindex
= vp
- simsp
;
3109 spindex
= ((flags
& JSV2F_SEARCH_STACK
) ? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK
);
3111 js_ReportValueError3(cx
, error
, spindex
, *vp
, NULL
, name
, source
);
3115 JSFunction::lastArg() const
3117 const Shape
*shape
= lastVar();
3118 if (u
.i
.nvars
!= 0) {
3119 while (shape
->previous() && shape
->getter() != js_GetCallArg
)
3120 shape
= shape
->previous();
3126 JSFunction::lastVar() const
3128 const Shape
*shape
= u
.i
.names
;
3129 if (u
.i
.nupvars
!= 0) {
3130 while (shape
->getter() == GetFlatUpvar
)
3131 shape
= shape
->previous();
3137 JSFunction::addLocal(JSContext
*cx
, JSAtom
*atom
, JSLocalKind kind
)
3139 JS_ASSERT(FUN_INTERPRETED(this));
3140 JS_ASSERT(!u
.i
.script
);
3143 * We still follow 10.2.3 of ES3 and make argument and variable properties
3144 * of the Call objects enumerable. ES5 reformulated all of its Clause 10 to
3145 * avoid objects as activations, something we should do too.
3147 uintN attrs
= JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_SHARED
;
3149 PropertyOp getter
, setter
;
3150 uint32 slot
= JSSLOT_START(&js_CallClass
) + JSObject::CALL_RESERVED_SLOTS
;
3152 if (kind
== JSLOCAL_ARG
) {
3153 JS_ASSERT(u
.i
.nupvars
== 0);
3156 getter
= js_GetCallArg
;
3157 setter
= SetCallArg
;
3159 } else if (kind
== JSLOCAL_UPVAR
) {
3160 indexp
= &u
.i
.nupvars
;
3161 getter
= GetFlatUpvar
;
3162 setter
= SetFlatUpvar
;
3163 slot
= SHAPE_INVALID_SLOT
;
3165 JS_ASSERT(u
.i
.nupvars
== 0);
3167 indexp
= &u
.i
.nvars
;
3168 getter
= js_GetCallVar
;
3169 setter
= SetCallVar
;
3170 if (kind
== JSLOCAL_CONST
)
3171 attrs
|= JSPROP_READONLY
;
3173 JS_ASSERT(kind
== JSLOCAL_VAR
);
3174 slot
+= nargs
+ u
.i
.nvars
;
3177 if (*indexp
== JS_BITMASK(16)) {
3178 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3179 (kind
== JSLOCAL_ARG
)
3180 ? JSMSG_TOO_MANY_FUN_ARGS
3181 : JSMSG_TOO_MANY_LOCALS
);
3185 Shape
**listp
= &u
.i
.names
;
3186 Shape
*parent
= *listp
;
3190 * The destructuring formal parameter parser adds a null atom, which we
3191 * encode as an INT id. The parser adds such locals after adding vars for
3192 * the destructured-to parameter bindings -- those must be vars to avoid
3193 * aliasing arguments[i] for any i -- so we must switch u.i.names to a
3194 * dictionary list to cope with insertion "in the middle" of an index-named
3195 * shape for the object or array argument.
3197 bool findArgInsertionPoint
= false;
3199 JS_ASSERT(kind
== JSLOCAL_ARG
);
3200 if (u
.i
.nvars
!= 0) {
3202 * A dictionary list needed only if the destructing pattern wasn't
3203 * empty, i.e., there were vars for its destructured-to bindings.
3205 if (!parent
->inDictionary() && !(parent
= Shape::newDictionaryList(cx
, listp
)))
3207 findArgInsertionPoint
= true;
3209 id
= INT_TO_JSID(nargs
);
3211 if (kind
== JSLOCAL_ARG
&& parent
->inDictionary())
3212 findArgInsertionPoint
= true;
3213 id
= ATOM_TO_JSID(atom
);
3216 if (findArgInsertionPoint
) {
3217 while (parent
->parent
&& parent
->getter() != js_GetCallArg
) {
3219 JS_ASSERT(parent
->slot
== parent
->slotSpan
);
3221 listp
= &parent
->parent
;
3226 Shape
child(id
, getter
, setter
, slot
, attrs
, Shape::HAS_SHORTID
, *indexp
);
3228 Shape
*shape
= parent
->getChild(cx
, child
, listp
);
3232 JS_ASSERT_IF(!shape
->inDictionary(), u
.i
.names
== shape
);
3238 JSFunction::lookupLocal(JSContext
*cx
, JSAtom
*atom
, uintN
*indexp
)
3240 JS_ASSERT(FUN_INTERPRETED(this));
3242 Shape
*shape
= SHAPE_FETCH(Shape::search(&u
.i
.names
, ATOM_TO_JSID(atom
)));
3244 JSLocalKind localKind
;
3246 if (shape
->getter() == js_GetCallArg
)
3247 localKind
= JSLOCAL_ARG
;
3248 else if (shape
->getter() == GetFlatUpvar
)
3249 localKind
= JSLOCAL_UPVAR
;
3250 else if (!shape
->writable())
3251 localKind
= JSLOCAL_CONST
;
3253 localKind
= JSLOCAL_VAR
;
3256 *indexp
= shape
->shortid
;
3259 return JSLOCAL_NONE
;
3263 JSFunction::getLocalNameArray(JSContext
*cx
, JSArenaPool
*pool
)
3265 JS_ASSERT(hasLocalNames());
3267 uintN n
= countLocalNames();
3271 * No need to check for overflow of the allocation size as we are making a
3272 * copy of already allocated data. As such it must fit size_t.
3274 JS_ARENA_ALLOCATE_CAST(names
, jsuword
*, pool
, size_t(n
) * sizeof *names
);
3276 js_ReportOutOfScriptQuota(cx
);
3281 for (uintN i
= 0; i
!= n
; i
++)
3282 names
[i
] = 0xdeadbeef;
3285 for (Shape::Range r
= u
.i
.names
; !r
.empty(); r
.popFront()) {
3286 const Shape
&shape
= r
.front();
3287 uintN index
= uint16(shape
.shortid
);
3288 jsuword constFlag
= 0;
3290 if (shape
.getter() == js_GetCallArg
) {
3291 JS_ASSERT(index
< nargs
);
3292 } else if (shape
.getter() == GetFlatUpvar
) {
3293 JS_ASSERT(index
< u
.i
.nupvars
);
3294 index
+= nargs
+ u
.i
.nvars
;
3296 JS_ASSERT(index
< u
.i
.nvars
);
3298 if (!shape
.writable())
3303 if (JSID_IS_ATOM(shape
.id
)) {
3304 atom
= JSID_TO_ATOM(shape
.id
);
3306 JS_ASSERT(JSID_IS_INT(shape
.id
));
3307 JS_ASSERT(shape
.getter() == js_GetCallArg
);
3311 names
[index
] = jsuword(atom
);
3315 for (uintN i
= 0; i
!= n
; i
++)
3316 JS_ASSERT(names
[i
] != 0xdeadbeef);
3322 JSFunction::freezeLocalNames(JSContext
*cx
)
3324 JS_ASSERT(FUN_INTERPRETED(this));
3326 Shape
*shape
= u
.i
.names
;
3327 if (shape
->inDictionary()) {
3329 JS_ASSERT(!shape
->frozen());
3331 } while ((shape
= shape
->parent
) != NULL
);
3336 * This method is called only if we parsed a duplicate formal. Let's use the
3337 * simplest possible algorithm, risking O(n^2) pain -- anyone dup'ing formals
3341 JSFunction::findDuplicateFormal() const
3343 JS_ASSERT(isInterpreted());
3348 for (Shape::Range r
= lastArg(); !r
.empty(); r
.popFront()) {
3349 const Shape
&shape
= r
.front();
3350 for (Shape::Range r2
= shape
.previous(); !r2
.empty(); r2
.popFront()) {
3351 if (r2
.front().id
== shape
.id
)
3352 return JSID_TO_ATOM(shape
.id
);