1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
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 */
73 /* Generic function/call/arguments tinyids -- also reflected bit numbers. */
75 CALL_ARGUMENTS
= -1, /* predefined arguments local variable */
76 ARGS_LENGTH
= -2, /* number of actual args, arity if inactive */
77 ARGS_CALLEE
= -3, /* reference from arguments to active funobj */
78 FUN_ARITY
= -4, /* number of formal parameters; desired argc */
79 FUN_NAME
= -5, /* function name, "" if anonymous */
80 FUN_CALLER
= -6 /* Function.prototype.caller, backward compat */
83 #if JSFRAME_OVERRIDE_BITS < 8
84 # error "not enough override bits in JSStackFrame.flags!"
87 #define TEST_OVERRIDE_BIT(fp, tinyid) \
88 ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
90 #define SET_OVERRIDE_BIT(fp, tinyid) \
91 ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
94 js_GetArgsValue(JSContext
*cx
, JSStackFrame
*fp
, jsval
*vp
)
98 if (TEST_OVERRIDE_BIT(fp
, CALL_ARGUMENTS
)) {
99 JS_ASSERT(fp
->callobj
);
100 return OBJ_GET_PROPERTY(cx
, fp
->callobj
,
101 ATOM_TO_JSID(cx
->runtime
->atomState
105 argsobj
= js_GetArgsObject(cx
, fp
);
108 *vp
= OBJECT_TO_JSVAL(argsobj
);
113 MarkArgDeleted(JSContext
*cx
, JSStackFrame
*fp
, uintN slot
)
116 jsval bmapval
, bmapint
;
117 size_t nbits
, nbytes
;
120 argsobj
= fp
->argsobj
;
121 (void) JS_GetReservedSlot(cx
, argsobj
, 0, &bmapval
);
123 JS_ASSERT(slot
< nbits
);
124 if (JSVAL_IS_VOID(bmapval
)) {
125 if (nbits
<= JSVAL_INT_BITS
) {
127 bitmap
= (jsbitmap
*) &bmapint
;
129 nbytes
= JS_HOWMANY(nbits
, JS_BITS_PER_WORD
) * sizeof(jsbitmap
);
130 bitmap
= (jsbitmap
*) JS_malloc(cx
, nbytes
);
133 memset(bitmap
, 0, nbytes
);
134 bmapval
= PRIVATE_TO_JSVAL(bitmap
);
135 JS_SetReservedSlot(cx
, argsobj
, 0, bmapval
);
138 if (nbits
<= JSVAL_INT_BITS
) {
139 bmapint
= JSVAL_TO_INT(bmapval
);
140 bitmap
= (jsbitmap
*) &bmapint
;
142 bitmap
= (jsbitmap
*) JSVAL_TO_PRIVATE(bmapval
);
145 JS_SET_BIT(bitmap
, slot
);
146 if (bitmap
== (jsbitmap
*) &bmapint
) {
147 bmapval
= INT_TO_JSVAL(bmapint
);
148 JS_SetReservedSlot(cx
, argsobj
, 0, bmapval
);
153 /* NB: Infallible predicate, false does not mean error/exception. */
155 ArgWasDeleted(JSContext
*cx
, JSStackFrame
*fp
, uintN slot
)
158 jsval bmapval
, bmapint
;
161 argsobj
= fp
->argsobj
;
162 (void) JS_GetReservedSlot(cx
, argsobj
, 0, &bmapval
);
163 if (JSVAL_IS_VOID(bmapval
))
165 if (fp
->argc
<= JSVAL_INT_BITS
) {
166 bmapint
= JSVAL_TO_INT(bmapval
);
167 bitmap
= (jsbitmap
*) &bmapint
;
169 bitmap
= (jsbitmap
*) JSVAL_TO_PRIVATE(bmapval
);
171 return JS_TEST_BIT(bitmap
, slot
) != 0;
175 js_GetArgsProperty(JSContext
*cx
, JSStackFrame
*fp
, jsid id
, jsval
*vp
)
181 if (TEST_OVERRIDE_BIT(fp
, CALL_ARGUMENTS
)) {
182 JS_ASSERT(fp
->callobj
);
183 if (!OBJ_GET_PROPERTY(cx
, fp
->callobj
,
184 ATOM_TO_JSID(cx
->runtime
->atomState
189 if (JSVAL_IS_PRIMITIVE(val
)) {
190 obj
= js_ValueToNonNullObject(cx
, val
);
194 obj
= JSVAL_TO_OBJECT(val
);
196 return OBJ_GET_PROPERTY(cx
, obj
, id
, vp
);
200 if (JSID_IS_INT(id
)) {
201 slot
= (uintN
) JSID_TO_INT(id
);
202 if (slot
< fp
->argc
) {
203 if (fp
->argsobj
&& ArgWasDeleted(cx
, fp
, slot
))
204 return OBJ_GET_PROPERTY(cx
, fp
->argsobj
, id
, vp
);
205 *vp
= fp
->argv
[slot
];
208 * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
209 * storage between the formal parameter and arguments[k] for all
210 * fp->argc <= k && k < fp->fun->nargs. For example, in
212 * function f(x) { x = 42; return arguments[0]; }
215 * the call to f should return undefined, not 42. If fp->argsobj
216 * is null at this point, as it would be in the example, return
220 return OBJ_GET_PROPERTY(cx
, fp
->argsobj
, id
, vp
);
223 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)) {
224 if (fp
->argsobj
&& TEST_OVERRIDE_BIT(fp
, ARGS_LENGTH
))
225 return OBJ_GET_PROPERTY(cx
, fp
->argsobj
, id
, vp
);
226 *vp
= INT_TO_JSVAL((jsint
) fp
->argc
);
233 js_GetArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
235 JSObject
*argsobj
, *global
, *parent
;
238 * We must be in a function activation; the function must be lightweight
239 * or else fp must have a variable object.
241 JS_ASSERT(fp
->fun
&& (!(fp
->fun
->flags
& JSFUN_HEAVYWEIGHT
) || fp
->varobj
));
243 /* Skip eval and debugger frames. */
244 while (fp
->flags
& JSFRAME_SPECIAL
)
247 /* Create an arguments object for fp only if it lacks one. */
248 argsobj
= fp
->argsobj
;
252 /* Link the new object to fp so it can get actual argument values. */
253 argsobj
= js_NewObject(cx
, &js_ArgumentsClass
, NULL
, NULL
);
254 if (!argsobj
|| !JS_SetPrivate(cx
, argsobj
, fp
)) {
255 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
260 * Give arguments an intrinsic scope chain link to fp's global object.
261 * Since the arguments object lacks a prototype because js_ArgumentsClass
262 * is not initialized, js_NewObject won't assign a default parent to it.
264 * Therefore if arguments is used as the head of an eval scope chain (via
265 * a direct or indirect call to eval(program, arguments)), any reference
266 * to a standard class object in the program will fail to resolve due to
267 * js_GetClassPrototype not being able to find a global object containing
268 * the standard prototype by starting from arguments and following parent.
270 global
= fp
->scopeChain
;
271 while ((parent
= OBJ_GET_PARENT(cx
, global
)) != NULL
)
273 STOBJ_SET_PARENT(argsobj
, global
);
274 fp
->argsobj
= argsobj
;
279 args_enumerate(JSContext
*cx
, JSObject
*obj
);
282 js_PutArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
290 * Reuse args_enumerate here to reflect fp's actual arguments as indexed
291 * elements of argsobj. Do this first, before clearing and freeing the
292 * deleted argument slot bitmap, because args_enumerate depends on that.
294 argsobj
= fp
->argsobj
;
295 ok
= args_enumerate(cx
, argsobj
);
298 * Now clear the deleted argument number bitmap slot and free the bitmap,
299 * if one was actually created due to 'delete arguments[0]' or similar.
301 (void) JS_GetReservedSlot(cx
, argsobj
, 0, &bmapval
);
302 if (!JSVAL_IS_VOID(bmapval
)) {
303 JS_SetReservedSlot(cx
, argsobj
, 0, JSVAL_VOID
);
304 if (fp
->argc
> JSVAL_INT_BITS
)
305 JS_free(cx
, JSVAL_TO_PRIVATE(bmapval
));
309 * Now get the prototype properties so we snapshot fp->fun and fp->argc
310 * before fp goes away.
313 ok
&= js_GetProperty(cx
, argsobj
, ATOM_TO_JSID(rt
->atomState
.calleeAtom
),
315 ok
&= js_SetProperty(cx
, argsobj
, ATOM_TO_JSID(rt
->atomState
.calleeAtom
),
317 ok
&= js_GetProperty(cx
, argsobj
, ATOM_TO_JSID(rt
->atomState
.lengthAtom
),
319 ok
&= js_SetProperty(cx
, argsobj
, ATOM_TO_JSID(rt
->atomState
.lengthAtom
),
323 * Clear the private pointer to fp, which is about to go away (js_Invoke).
324 * Do this last because the args_enumerate and js_GetProperty calls above
325 * need to follow the private slot to find fp.
327 ok
&= JS_SetPrivate(cx
, argsobj
, NULL
);
333 args_delProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
338 if (!JSVAL_IS_INT(id
))
340 fp
= (JSStackFrame
*)
341 JS_GetInstancePrivate(cx
, obj
, &js_ArgumentsClass
, NULL
);
344 JS_ASSERT(fp
->argsobj
);
346 slot
= JSVAL_TO_INT(id
);
350 SET_OVERRIDE_BIT(fp
, slot
);
354 if ((uintN
)slot
< fp
->argc
&& !MarkArgDeleted(cx
, fp
, slot
))
362 args_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
367 if (!JSVAL_IS_INT(id
))
369 fp
= (JSStackFrame
*)
370 JS_GetInstancePrivate(cx
, obj
, &js_ArgumentsClass
, NULL
);
373 JS_ASSERT(fp
->argsobj
);
375 slot
= JSVAL_TO_INT(id
);
378 if (!TEST_OVERRIDE_BIT(fp
, slot
))
379 *vp
= OBJECT_TO_JSVAL(fp
->callee
);
383 if (!TEST_OVERRIDE_BIT(fp
, slot
))
384 *vp
= INT_TO_JSVAL((jsint
)fp
->argc
);
388 if ((uintN
)slot
< fp
->argc
&& !ArgWasDeleted(cx
, fp
, slot
))
389 *vp
= fp
->argv
[slot
];
396 args_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
401 if (!JSVAL_IS_INT(id
))
403 fp
= (JSStackFrame
*)
404 JS_GetInstancePrivate(cx
, obj
, &js_ArgumentsClass
, NULL
);
407 JS_ASSERT(fp
->argsobj
);
409 slot
= JSVAL_TO_INT(id
);
413 SET_OVERRIDE_BIT(fp
, slot
);
417 if (FUN_INTERPRETED(fp
->fun
) &&
418 (uintN
)slot
< fp
->argc
&&
419 !ArgWasDeleted(cx
, fp
, slot
)) {
420 fp
->argv
[slot
] = *vp
;
428 args_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
439 fp
= (JSStackFrame
*)
440 JS_GetInstancePrivate(cx
, obj
, &js_ArgumentsClass
, NULL
);
443 JS_ASSERT(fp
->argsobj
);
445 if (JSVAL_IS_INT(id
)) {
446 slot
= JSVAL_TO_INT(id
);
447 if (slot
< fp
->argc
&& !ArgWasDeleted(cx
, fp
, slot
)) {
448 /* XXX ECMA specs DontEnum, contrary to other array-like objects */
449 if (!js_DefineProperty(cx
, obj
, INT_JSVAL_TO_JSID(id
),
451 args_getProperty
, args_setProperty
,
458 str
= JSVAL_TO_STRING(id
);
459 atom
= cx
->runtime
->atomState
.lengthAtom
;
460 if (str
== ATOM_TO_STRING(atom
)) {
461 tinyid
= ARGS_LENGTH
;
462 value
= INT_TO_JSVAL(fp
->argc
);
464 atom
= cx
->runtime
->atomState
.calleeAtom
;
465 if (str
== ATOM_TO_STRING(atom
)) {
466 tinyid
= ARGS_CALLEE
;
467 value
= OBJECT_TO_JSVAL(fp
->callee
);
471 /* Quell GCC overwarnings. */
477 if (atom
&& !TEST_OVERRIDE_BIT(fp
, tinyid
)) {
478 if (!js_DefineNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
), value
,
479 args_getProperty
, args_setProperty
, 0,
480 SPROP_HAS_SHORTID
, tinyid
, NULL
)) {
491 args_enumerate(JSContext
*cx
, JSObject
*obj
)
498 fp
= (JSStackFrame
*)
499 JS_GetInstancePrivate(cx
, obj
, &js_ArgumentsClass
, NULL
);
502 JS_ASSERT(fp
->argsobj
);
505 * Trigger reflection with value snapshot in args_resolve using a series
506 * of js_LookupProperty calls. We handle length, callee, and the indexed
507 * argument properties. We know that args_resolve covers all these cases
508 * and creates direct properties of obj, but that it may fail to resolve
509 * length or callee if overridden.
511 if (!js_LookupProperty(cx
, obj
,
512 ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
),
517 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
519 if (!js_LookupProperty(cx
, obj
,
520 ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
),
525 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
528 for (slot
= 0; slot
< argc
; slot
++) {
529 if (!js_LookupProperty(cx
, obj
, INT_TO_JSID((jsint
)slot
), &pobj
, &prop
))
532 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
537 #if JS_HAS_GENERATORS
539 * If a generator-iterator's arguments or call object escapes, it needs to
540 * mark its generator object.
543 args_or_call_trace(JSTracer
*trc
, JSObject
*obj
)
547 fp
= (JSStackFrame
*) JS_GetPrivate(trc
->context
, obj
);
548 if (fp
&& (fp
->flags
& JSFRAME_GENERATOR
)) {
549 JS_CALL_OBJECT_TRACER(trc
, FRAME_TO_GENERATOR(fp
)->obj
,
550 "FRAME_TO_GENERATOR(fp)->obj");
554 # define args_or_call_trace NULL
558 * The Arguments class is not initialized via JS_InitClass, and must not be,
559 * because its name is "Object". Per ECMA, that causes instances of it to
560 * delegate to the object named by Object.prototype. It also ensures that
561 * arguments.toString() returns "[object Object]".
563 * The JSClass functions below collaborate to lazily reflect and synchronize
564 * actual argument values, argument count, and callee function object stored
565 * in a JSStackFrame with their corresponding property values in the frame's
568 JSClass js_ArgumentsClass
= {
570 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
| JSCLASS_HAS_RESERVED_SLOTS(1) |
571 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
572 JS_PropertyStub
, args_delProperty
,
573 args_getProperty
, args_setProperty
,
574 args_enumerate
, (JSResolveOp
) args_resolve
,
575 JS_ConvertStub
, JS_FinalizeStub
,
579 JS_CLASS_TRACE(args_or_call_trace
), NULL
583 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
, JSObject
*parent
)
585 JSObject
*callobj
, *funobj
;
587 /* Create a call object for fp only if it lacks one. */
589 callobj
= fp
->callobj
;
594 /* The default call parent is its function's parent (static link). */
598 parent
= OBJ_GET_PARENT(cx
, funobj
);
601 /* Create the call object and link it to its stack frame. */
602 callobj
= js_NewObject(cx
, &js_CallClass
, NULL
, parent
);
603 if (!callobj
|| !JS_SetPrivate(cx
, callobj
, fp
)) {
604 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
607 fp
->callobj
= callobj
;
609 /* Make callobj be the scope chain and the variables object. */
610 JS_ASSERT(fp
->scopeChain
== parent
);
611 fp
->scopeChain
= callobj
;
612 fp
->varobj
= callobj
;
617 call_enumerate(JSContext
*cx
, JSObject
*obj
);
620 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
)
628 * Reuse call_enumerate here to reflect all actual args and vars into the
629 * call object from fp.
631 callobj
= fp
->callobj
;
634 ok
= call_enumerate(cx
, callobj
);
637 * Get the arguments object to snapshot fp's actual argument values.
640 if (!TEST_OVERRIDE_BIT(fp
, CALL_ARGUMENTS
)) {
641 argsid
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
642 aval
= OBJECT_TO_JSVAL(fp
->argsobj
);
643 ok
&= js_SetProperty(cx
, callobj
, argsid
, &aval
);
645 ok
&= js_PutArgsObject(cx
, fp
);
649 * Clear the private pointer to fp, which is about to go away (js_Invoke).
650 * Do this last because the call_enumerate and js_GetProperty calls above
651 * need to follow the private slot to find fp.
653 ok
&= JS_SetPrivate(cx
, callobj
, NULL
);
659 call_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
664 if (!JSVAL_IS_INT(id
))
666 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
671 slot
= JSVAL_TO_INT(id
);
674 if (!TEST_OVERRIDE_BIT(fp
, slot
)) {
675 JSObject
*argsobj
= js_GetArgsObject(cx
, fp
);
678 *vp
= OBJECT_TO_JSVAL(argsobj
);
683 if ((uintN
)slot
< JS_MAX(fp
->argc
, fp
->fun
->nargs
))
684 *vp
= fp
->argv
[slot
];
691 call_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
696 if (!JSVAL_IS_INT(id
))
698 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
703 slot
= JSVAL_TO_INT(id
);
706 SET_OVERRIDE_BIT(fp
, slot
);
710 if ((uintN
)slot
< JS_MAX(fp
->argc
, fp
->fun
->nargs
))
711 fp
->argv
[slot
] = *vp
;
718 js_GetCallVariable(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
722 JS_ASSERT(JSVAL_IS_INT(id
));
723 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
725 /* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
726 if ((uintN
)JSVAL_TO_INT(id
) < fp
->nvars
)
727 *vp
= fp
->vars
[JSVAL_TO_INT(id
)];
733 js_SetCallVariable(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
737 JS_ASSERT(JSVAL_IS_INT(id
));
738 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
740 /* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
741 jsint slot
= JSVAL_TO_INT(id
);
742 if ((uintN
)slot
< fp
->nvars
)
743 fp
->vars
[slot
] = *vp
;
749 call_enumerate(JSContext
*cx
, JSObject
*obj
)
752 JSObject
*funobj
, *pobj
;
754 JSScopeProperty
*sprop
, *cprop
;
760 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
765 * Do not enumerate a cloned function object at fp->callee, it may have
766 * gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
767 * the clone's prototype property). We must enumerate the function object
768 * that was decorated with parameter and local variable properties by the
769 * compiler when the compiler created fp->fun, namely fp->fun->object.
771 * Contrast with call_resolve, where we prefer fp->callee, because we'll
772 * use js_LookupProperty to find any overridden properties in that object,
773 * if it was a mutated clone; and if not, we will search its prototype,
774 * fp->fun->object, to find compiler-created params and locals.
776 funobj
= fp
->fun
->object
;
781 * Reflect actual args from fp->argv for formal parameters, and local vars
782 * and functions in fp->vars for declared variables and nested-at-top-level
785 scope
= OBJ_SCOPE(funobj
);
786 for (sprop
= SCOPE_LAST_PROP(scope
); sprop
; sprop
= sprop
->parent
) {
787 getter
= sprop
->getter
;
788 if (getter
== js_GetArgument
)
790 else if (getter
== js_GetLocalVariable
)
795 /* Trigger reflection by looking up the unhidden atom for sprop->id. */
796 id
= JSID_UNHIDE_NAME(sprop
->id
);
797 if (!js_LookupProperty(cx
, obj
, id
, &pobj
, &prop
))
801 * If we found the property in a different object, don't try sticking
802 * it into wrong slots vector. This can occur because we have a mutable
803 * __proto__ slot, and cloned function objects rely on their __proto__
804 * to delegate to the object that contains the var and arg properties.
806 if (!prop
|| pobj
!= obj
) {
808 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
811 cprop
= (JSScopeProperty
*)prop
;
812 LOCKED_OBJ_SET_SLOT(obj
, cprop
->slot
, vec
[(uint16
) sprop
->shortid
]);
813 OBJ_DROP_PROPERTY(cx
, obj
, prop
);
820 call_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
829 JSScopeProperty
*sprop
;
830 JSPropertyOp getter
, setter
;
831 uintN attrs
, slot
, nslots
, spflags
;
835 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
840 if (!JSVAL_IS_STRING(id
))
846 JS_ASSERT((JSFunction
*) OBJ_GET_PRIVATE(cx
, funobj
) == fp
->fun
);
848 str
= JSVAL_TO_STRING(id
);
849 atom
= js_AtomizeString(cx
, str
, 0);
852 if (!js_LookupHiddenProperty(cx
, funobj
, ATOM_TO_JSID(atom
), &obj2
, &prop
))
856 if (!OBJ_IS_NATIVE(obj2
)) {
857 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
861 sprop
= (JSScopeProperty
*) prop
;
862 getter
= sprop
->getter
;
863 attrs
= sprop
->attrs
& ~JSPROP_SHARED
;
864 slot
= (uintN
) sprop
->shortid
;
865 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
867 /* Ensure we found an arg or var property for the same function. */
868 if ((sprop
->flags
& SPROP_IS_HIDDEN
) &&
870 (JSFunction
*) OBJ_GET_PRIVATE(cx
, obj2
) == fp
->fun
)) {
871 if (getter
== js_GetArgument
) {
873 nslots
= JS_MAX(fp
->argc
, fp
->fun
->nargs
);
874 getter
= setter
= NULL
;
876 JS_ASSERT(getter
== js_GetLocalVariable
);
879 getter
= js_GetCallVariable
;
880 setter
= js_SetCallVariable
;
884 spflags
= SPROP_HAS_SHORTID
;
885 shortid
= (intN
) slot
;
891 if (!js_DefineNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
), value
,
892 getter
, setter
, attrs
,
893 spflags
, shortid
, NULL
)) {
901 if (!(flags
& JSRESOLVE_ASSIGNING
)) {
903 * Resolve arguments so that we never store a particular Call object's
904 * arguments object reference in a Call prototype's |arguments| slot.
906 atom
= cx
->runtime
->atomState
.argumentsAtom
;
907 if (id
== ATOM_KEY(atom
)) {
908 if (!js_DefineNativeProperty(cx
, obj
,
909 ATOM_TO_JSID(atom
), JSVAL_VOID
,
910 NULL
, NULL
, JSPROP_PERMANENT
,
911 SPROP_HAS_SHORTID
, CALL_ARGUMENTS
,
923 call_convert(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
927 if (type
== JSTYPE_FUNCTION
) {
928 fp
= (JSStackFrame
*) JS_GetPrivate(cx
, obj
);
931 *vp
= OBJECT_TO_JSVAL(fp
->callee
);
937 JSClass js_CallClass
= {
939 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
| JSCLASS_IS_ANONYMOUS
|
940 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Call
),
941 JS_PropertyStub
, JS_PropertyStub
,
942 call_getProperty
, call_setProperty
,
943 call_enumerate
, (JSResolveOp
)call_resolve
,
944 call_convert
, JS_FinalizeStub
,
948 JS_CLASS_TRACE(args_or_call_trace
), NULL
,
952 * ECMA-262 specifies that length is a property of function object instances,
953 * but we can avoid that space cost by delegating to a prototype property that
954 * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes
955 * a fresh length value based on the arity of the individual function object's
958 * The extensions below other than length, i.e., the ones not in ECMA-262,
959 * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
960 * with ECMA we must allow a delegating object to override them. Therefore to
961 * avoid entraining garbage in Function.prototype slots, they must be resolved
962 * in non-prototype function objects, wherefore the lazy_function_props table
963 * and fun_resolve's use of it.
965 #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
967 static JSPropertySpec function_props
[] = {
968 {js_length_str
, ARGS_LENGTH
, LENGTH_PROP_ATTRS
, 0,0},
972 typedef struct LazyFunctionProp
{
978 /* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
979 static LazyFunctionProp lazy_function_props
[] = {
980 {ATOM_OFFSET(arguments
), CALL_ARGUMENTS
, JSPROP_PERMANENT
},
981 {ATOM_OFFSET(arity
), FUN_ARITY
, JSPROP_PERMANENT
},
982 {ATOM_OFFSET(caller
), FUN_CALLER
, JSPROP_PERMANENT
},
983 {ATOM_OFFSET(name
), FUN_NAME
, JSPROP_PERMANENT
},
987 fun_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
993 if (!JSVAL_IS_INT(id
))
995 slot
= JSVAL_TO_INT(id
);
998 * Loop because getter and setter can be delegated from another class,
999 * but loop only for ARGS_LENGTH because we must pretend that f.length
1000 * is in each function instance f, per ECMA-262, instead of only in the
1001 * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1002 * to make it appear so).
1004 * This code couples tightly to the attributes for the function_props[]
1005 * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper.
1007 * It's important to allow delegating objects, even though they inherit
1008 * this getter (fun_getProperty), to override arguments, arity, caller,
1009 * and name. If we didn't return early for slot != ARGS_LENGTH, we would
1010 * clobber *vp with the native property value, instead of letting script
1011 * override that value in delegating objects.
1013 * Note how that clobbering is what simulates JSPROP_READONLY for all of
1014 * the non-standard properties when the directly addressed object (obj)
1015 * is a function object (i.e., when this loop does not iterate).
1017 while (!(fun
= (JSFunction
*)
1018 JS_GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
))) {
1019 if (slot
!= ARGS_LENGTH
)
1021 obj
= OBJ_GET_PROTO(cx
, obj
);
1026 /* Find fun's top-most activation record. */
1027 for (fp
= cx
->fp
; fp
&& (fp
->fun
!= fun
|| (fp
->flags
& JSFRAME_SPECIAL
));
1033 case CALL_ARGUMENTS
:
1034 /* Warn if strict about f.arguments or equivalent unqualified uses. */
1035 if (!JS_ReportErrorFlagsAndNumber(cx
,
1036 JSREPORT_WARNING
| JSREPORT_STRICT
,
1037 js_GetErrorMessage
, NULL
,
1038 JSMSG_DEPRECATED_USAGE
,
1039 js_arguments_str
)) {
1043 if (!js_GetArgsValue(cx
, fp
, vp
))
1052 *vp
= INT_TO_JSVAL((jsint
)fun
->nargs
);
1057 ? ATOM_KEY(fun
->atom
)
1058 : STRING_TO_JSVAL(cx
->runtime
->emptyString
);
1062 while (fp
&& (fp
->flags
& JSFRAME_SKIP_CALLER
) && fp
->down
)
1064 if (fp
&& fp
->down
&& fp
->down
->fun
)
1065 *vp
= OBJECT_TO_JSVAL(fp
->down
->callee
);
1068 if (!JSVAL_IS_PRIMITIVE(*vp
) && cx
->runtime
->checkObjectAccess
) {
1069 id
= ATOM_KEY(cx
->runtime
->atomState
.callerAtom
);
1070 if (!cx
->runtime
->checkObjectAccess(cx
, obj
, id
, JSACC_READ
, vp
))
1076 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1077 if (fp
&& fp
->fun
&& (uintN
)slot
< fp
->fun
->nargs
)
1078 *vp
= fp
->argv
[slot
];
1086 fun_enumerate(JSContext
*cx
, JSObject
*obj
)
1092 prototypeId
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1093 if (!OBJ_LOOKUP_PROPERTY(cx
, obj
, prototypeId
, &pobj
, &prop
))
1096 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
1101 fun_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
1108 if (!JSVAL_IS_STRING(id
))
1111 /* No valid function object should lack private data. */
1112 fun
= (JSFunction
*)JS_GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
);
1113 JS_ASSERT(fun
&& fun
->object
);
1116 * Check for a hidden formal parameter or local variable binding in the
1117 * clone-parent of obj, which would be a different, non-null fun->object.
1119 if (flags
& JSRESOLVE_HIDDEN
) {
1120 if (fun
->object
!= obj
) {
1124 atom
= js_AtomizeString(cx
, JSVAL_TO_STRING(id
), 0);
1127 if (!js_LookupHiddenProperty(cx
, fun
->object
, ATOM_TO_JSID(atom
),
1132 JS_ASSERT(pobj
== fun
->object
);
1134 OBJ_DROP_PROPERTY(cx
, pobj
, prop
);
1141 * No need to reflect fun.prototype in 'fun.prototype = ...'. This test
1142 * must come after the JSRESOLVE_HIDDEN test, since call_resolve may look
1143 * for a hidden function object property from an assignment bytecode.
1145 if (flags
& JSRESOLVE_ASSIGNING
)
1149 * Ok, check whether id is 'prototype' and bootstrap the function object's
1150 * prototype property.
1152 atom
= cx
->runtime
->atomState
.classPrototypeAtom
;
1153 if (id
== ATOM_KEY(atom
)) {
1154 JSObject
*proto
, *parentProto
;
1157 proto
= parentProto
= NULL
;
1158 if (fun
->object
!= obj
&&
1159 (!cx
->runtime
->findObjectPrincipals
||
1160 cx
->runtime
->findObjectPrincipals(cx
, obj
) ==
1161 cx
->runtime
->findObjectPrincipals(cx
, fun
->object
))) {
1163 * Clone of a function where the clone and the object owning fun
1164 * appear to be in the same trust domain: make the cloned function
1165 * object's 'prototype' property value have the same class as the
1166 * clone-parent's 'prototype' value.
1168 if (!OBJ_GET_PROPERTY(cx
, fun
->object
, ATOM_TO_JSID(atom
), &pval
))
1170 if (!JSVAL_IS_PRIMITIVE(pval
)) {
1172 * We are about to allocate a new object, so hack the newborn
1173 * root until then to protect pval in case it is figuratively
1174 * up in the air, with no strong refs protecting it.
1176 cx
->weakRoots
.newborn
[GCX_OBJECT
] =
1177 (JSGCThing
*)JSVAL_TO_GCTHING(pval
);
1178 parentProto
= JSVAL_TO_OBJECT(pval
);
1183 * Beware of the wacky case of a user function named Object -- trying
1184 * to find a prototype for that will recur back here _ad perniciem_.
1186 if (!parentProto
&& fun
->atom
== CLASS_ATOM(cx
, Object
))
1190 * If resolving "prototype" in a clone, clone the parent's prototype.
1191 * Pass the constructor's (obj's) parent as the prototype parent, to
1192 * avoid defaulting to parentProto.constructor.__parent__.
1194 proto
= js_NewObject(cx
, &js_ObjectClass
, parentProto
,
1195 OBJ_GET_PARENT(cx
, obj
));
1200 * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1201 * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1202 * native "system" constructors such as Object or Function. So lazily
1203 * set the former here in fun_resolve, but eagerly define the latter
1204 * in JS_InitClass, with the right attributes.
1206 if (!js_SetClassPrototype(cx
, obj
, proto
,
1207 JSPROP_ENUMERATE
| JSPROP_PERMANENT
)) {
1208 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
1215 for (i
= 0; i
< JS_ARRAY_LENGTH(lazy_function_props
); i
++) {
1216 LazyFunctionProp
*lfp
= &lazy_function_props
[i
];
1218 atom
= OFFSET_TO_ATOM(cx
->runtime
, lfp
->atomOffset
);
1219 if (id
== ATOM_KEY(atom
)) {
1220 if (!js_DefineNativeProperty(cx
, obj
,
1221 ATOM_TO_JSID(atom
), JSVAL_VOID
,
1222 NULL
, NULL
, lfp
->attrs
,
1223 SPROP_HAS_SHORTID
, lfp
->tinyid
,
1236 fun_convert(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
1239 case JSTYPE_FUNCTION
:
1240 *vp
= OBJECT_TO_JSVAL(obj
);
1243 return js_TryValueOf(cx
, obj
, type
, vp
);
1249 #include "jsxdrapi.h"
1257 /* XXX store parent and proto, if defined */
1259 fun_xdrObject(JSXDRState
*xdr
, JSObject
**objp
)
1263 uint32 nullAtom
; /* flag to indicate if fun->atom is NULL */
1264 JSTempValueRooter tvr
;
1265 uint32 flagsword
; /* originally only flags was JS_XDRUint8'd */
1266 uint16 extraUnused
; /* variable for no longer used field */
1268 JSScopeProperty
*sprop
;
1269 uint32 userid
; /* NB: holds a signed int-tagged jsval */
1270 uintN i
, n
, dupflag
;
1274 uintN nvars
= 0, nargs
= 0;
1278 if (xdr
->mode
== JSXDR_ENCODE
) {
1280 * No valid function object should lack private data, but fail soft
1281 * (return true, no error report) in case one does due to API pilot
1282 * or internal error.
1284 fun
= (JSFunction
*) OBJ_GET_PRIVATE(cx
, *objp
);
1287 if (!FUN_INTERPRETED(fun
)) {
1288 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1289 JSMSG_NOT_SCRIPTED_FUNCTION
,
1290 JS_GetFunctionName(fun
));
1293 nullAtom
= !fun
->atom
;
1294 flagsword
= fun
->flags
;
1297 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, 0, NULL
, NULL
);
1302 /* From here on, control flow must flow through label out. */
1303 JS_PUSH_TEMP_ROOT_OBJECT(cx
, fun
->object
, &tvr
);
1306 if (!JS_XDRUint32(xdr
, &nullAtom
))
1308 if (!nullAtom
&& !js_XDRStringAtom(xdr
, &fun
->atom
))
1311 if (!JS_XDRUint16(xdr
, &fun
->nargs
) ||
1312 !JS_XDRUint16(xdr
, &extraUnused
) ||
1313 !JS_XDRUint16(xdr
, &fun
->u
.i
.nvars
) ||
1314 !JS_XDRUint32(xdr
, &flagsword
)) {
1318 /* Assert that all previous writes of extraUnused were writes of 0. */
1319 JS_ASSERT(extraUnused
== 0);
1321 /* do arguments and local vars */
1323 n
= fun
->nargs
+ fun
->u
.i
.nvars
;
1324 if (xdr
->mode
== JSXDR_ENCODE
) {
1326 JSScopeProperty
**spvec
, *auto_spvec
[8];
1329 if (n
<= sizeof auto_spvec
/ sizeof auto_spvec
[0]) {
1333 mark
= JS_ARENA_MARK(&cx
->tempPool
);
1334 JS_ARENA_ALLOCATE_CAST(spvec
, JSScopeProperty
**, &cx
->tempPool
,
1335 n
* sizeof(JSScopeProperty
*));
1337 JS_ReportOutOfMemory(cx
);
1341 scope
= OBJ_SCOPE(fun
->object
);
1342 for (sprop
= SCOPE_LAST_PROP(scope
); sprop
;
1343 sprop
= sprop
->parent
) {
1344 if (sprop
->getter
== js_GetArgument
) {
1345 JS_ASSERT(nargs
++ <= fun
->nargs
);
1346 spvec
[sprop
->shortid
] = sprop
;
1347 } else if (sprop
->getter
== js_GetLocalVariable
) {
1348 JS_ASSERT(nvars
++ <= fun
->u
.i
.nvars
);
1349 spvec
[fun
->nargs
+ sprop
->shortid
] = sprop
;
1352 for (i
= 0; i
< n
; i
++) {
1354 JS_ASSERT(sprop
->flags
& SPROP_HAS_SHORTID
);
1355 type
= (i
< fun
->nargs
)
1357 : (sprop
->attrs
& JSPROP_READONLY
)
1360 userid
= INT_TO_JSVAL(sprop
->shortid
);
1363 * sprop->id here represents hidden names so we unhide it and
1364 * encode as an atom. During decoding we read the atom and use
1365 * js_AddHiddenProperty to reconstruct sprop with the hidden
1368 propAtom
= JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop
->id
));
1369 if (!JS_XDRUint32(xdr
, &type
) ||
1370 !JS_XDRUint32(xdr
, &userid
) ||
1371 !js_XDRStringAtom(xdr
, &propAtom
)) {
1373 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
1378 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
1380 JSPropertyOp getter
, setter
;
1382 for (i
= n
; i
!= 0; i
--) {
1383 uintN attrs
= JSPROP_PERMANENT
;
1385 if (!JS_XDRUint32(xdr
, &type
) ||
1386 !JS_XDRUint32(xdr
, &userid
) ||
1387 !js_XDRStringAtom(xdr
, &propAtom
)) {
1390 JS_ASSERT(type
== JSXDR_FUNARG
|| type
== JSXDR_FUNVAR
||
1391 type
== JSXDR_FUNCONST
);
1392 if (type
== JSXDR_FUNARG
) {
1393 getter
= js_GetArgument
;
1394 setter
= js_SetArgument
;
1395 JS_ASSERT(nargs
++ <= fun
->nargs
);
1396 } else if (type
== JSXDR_FUNVAR
|| type
== JSXDR_FUNCONST
) {
1397 getter
= js_GetLocalVariable
;
1398 setter
= js_SetLocalVariable
;
1399 if (type
== JSXDR_FUNCONST
)
1400 attrs
|= JSPROP_READONLY
;
1401 JS_ASSERT(nvars
++ <= fun
->u
.i
.nvars
);
1407 /* Flag duplicate argument if atom is bound in fun->object. */
1408 dupflag
= SCOPE_GET_PROPERTY(OBJ_SCOPE(fun
->object
),
1409 ATOM_TO_JSID(propAtom
))
1410 ? SPROP_IS_DUPLICATE
1413 if (!js_AddHiddenProperty(cx
, fun
->object
,
1414 ATOM_TO_JSID(propAtom
),
1415 getter
, setter
, SPROP_INVALID_SLOT
,
1416 attrs
| JSPROP_SHARED
,
1417 dupflag
| SPROP_HAS_SHORTID
,
1418 JSVAL_TO_INT(userid
))) {
1425 if (!js_XDRScript(xdr
, &fun
->u
.i
.script
, NULL
))
1428 if (xdr
->mode
== JSXDR_DECODE
) {
1429 fun
->flags
= (uint16
) flagsword
| JSFUN_INTERPRETED
;
1431 *objp
= fun
->object
;
1432 js_CallNewScriptHook(cx
, fun
->u
.i
.script
, fun
);
1436 JS_POP_TEMP_ROOT(cx
, &tvr
);
1444 #else /* !JS_HAS_XDR */
1446 #define fun_xdrObject NULL
1448 #endif /* !JS_HAS_XDR */
1451 * [[HasInstance]] internal method for Function objects: fetch the .prototype
1452 * property of its 'this' parameter, and walks the prototype chain of v (only
1453 * if v is an object) returning true if .prototype is found.
1456 fun_hasInstance(JSContext
*cx
, JSObject
*obj
, jsval v
, JSBool
*bp
)
1460 if (!OBJ_GET_PROPERTY(cx
, obj
,
1461 ATOM_TO_JSID(cx
->runtime
->atomState
1462 .classPrototypeAtom
),
1467 if (JSVAL_IS_PRIMITIVE(pval
)) {
1469 * Throw a runtime error if instanceof is called on a function that
1470 * has a non-object as its .prototype value.
1472 js_ReportValueError(cx
, JSMSG_BAD_PROTOTYPE
,
1473 -1, OBJECT_TO_JSVAL(obj
), NULL
);
1477 return js_IsDelegate(cx
, JSVAL_TO_OBJECT(pval
), v
, bp
);
1481 fun_trace(JSTracer
*trc
, JSObject
*obj
)
1485 fun
= (JSFunction
*) JS_GetPrivate(trc
->context
, obj
);
1487 JS_CALL_TRACER(trc
, fun
, JSTRACE_FUNCTION
, "private");
1488 if (fun
->object
!= obj
)
1489 JS_CALL_TRACER(trc
, fun
->object
, JSTRACE_OBJECT
, "object");
1491 JS_CALL_STRING_TRACER(trc
, ATOM_TO_STRING(fun
->atom
), "atom");
1492 if (FUN_INTERPRETED(fun
) && fun
->u
.i
.script
)
1493 js_TraceScript(trc
, fun
->u
.i
.script
);
1498 fun_reserveSlots(JSContext
*cx
, JSObject
*obj
)
1502 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
1503 return (fun
&& FUN_INTERPRETED(fun
) &&
1504 fun
->u
.i
.script
&& fun
->u
.i
.script
->regexpsOffset
!= 0)
1505 ? JS_SCRIPT_REGEXPS(fun
->u
.i
.script
)->length
1510 * Reserve two slots in all function objects for XPConnect. Note that this
1511 * does not bloat every instance, only those on which reserved slots are set,
1512 * and those on which ad-hoc properties are defined.
1514 JS_FRIEND_DATA(JSClass
) js_FunctionClass
= {
1516 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
| JSCLASS_HAS_RESERVED_SLOTS(2) |
1517 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Function
),
1518 JS_PropertyStub
, JS_PropertyStub
,
1519 fun_getProperty
, JS_PropertyStub
,
1520 fun_enumerate
, (JSResolveOp
)fun_resolve
,
1521 fun_convert
, JS_FinalizeStub
,
1524 fun_xdrObject
, fun_hasInstance
,
1525 JS_CLASS_TRACE(fun_trace
), fun_reserveSlots
1529 fun_toStringHelper(JSContext
*cx
, uint32 indent
, uintN argc
, jsval
*vp
)
1537 if (!VALUE_IS_FUNCTION(cx
, fval
)) {
1539 * If we don't have a function to start off with, try converting the
1540 * object to a function. If that doesn't work, complain.
1542 if (!JSVAL_IS_PRIMITIVE(fval
)) {
1543 obj
= JSVAL_TO_OBJECT(fval
);
1544 if (!OBJ_GET_CLASS(cx
, obj
)->convert(cx
, obj
, JSTYPE_FUNCTION
,
1550 if (!VALUE_IS_FUNCTION(cx
, fval
)) {
1551 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1552 JSMSG_INCOMPATIBLE_PROTO
,
1553 js_Function_str
, js_toString_str
,
1554 JS_GetTypeName(cx
, JS_TypeOfValue(cx
, fval
)));
1559 obj
= JSVAL_TO_OBJECT(fval
);
1560 if (argc
!= 0 && !js_ValueToECMAUint32(cx
, vp
[2], &indent
))
1563 JS_ASSERT(JS_ObjectIsFunction(cx
, obj
));
1564 fun
= (JSFunction
*) OBJ_GET_PRIVATE(cx
, obj
);
1567 str
= JS_DecompileFunction(cx
, fun
, (uintN
)indent
);
1570 *vp
= STRING_TO_JSVAL(str
);
1575 fun_toString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1577 return fun_toStringHelper(cx
, 0, argc
, vp
);
1582 fun_toSource(JSContext
*cx
, uintN argc
, jsval
*vp
)
1584 return fun_toStringHelper(cx
, JS_DONT_PRETTY_PRINT
, argc
, vp
);
1588 static const char call_str
[] = "call";
1591 fun_call(JSContext
*cx
, uintN argc
, jsval
*vp
)
1594 jsval fval
, *argv
, *sp
, *oldsp
;
1601 obj
= JSVAL_TO_OBJECT(vp
[1]);
1602 if (!OBJ_DEFAULT_VALUE(cx
, obj
, JSTYPE_FUNCTION
, &vp
[1]))
1606 if (!VALUE_IS_FUNCTION(cx
, fval
)) {
1607 str
= JS_ValueToString(cx
, fval
);
1609 const char *bytes
= js_GetStringBytes(cx
, str
);
1612 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1613 JSMSG_INCOMPATIBLE_PROTO
,
1614 js_Function_str
, call_str
,
1623 /* Call fun with its global object as the 'this' param if no args. */
1626 /* Otherwise convert the first arg to 'this' and skip over it. */
1627 if (!JSVAL_IS_PRIMITIVE(argv
[0]))
1628 obj
= JSVAL_TO_OBJECT(argv
[0]);
1629 else if (!js_ValueToObject(cx
, argv
[0], &obj
))
1635 /* Allocate stack space for fval, obj, and the args. */
1636 sp
= js_AllocStack(cx
, 2 + argc
, &mark
);
1640 /* Push fval, obj, and the args. */
1642 *sp
++ = OBJECT_TO_JSVAL(obj
);
1643 for (i
= 0; i
< argc
; i
++)
1646 /* Lift current frame to include the args and do the call. */
1650 ok
= js_Invoke(cx
, argc
,
1651 (fp
->flags
& JSFRAME_IN_FAST_CALL
)
1653 : JSINVOKE_INTERNAL
| JSINVOKE_SKIP_CALLER
);
1655 /* Store rval and pop stack back to our frame's sp. */
1658 js_FreeStack(cx
, mark
);
1663 fun_apply(JSContext
*cx
, uintN argc
, jsval
*vp
)
1665 JSObject
*obj
, *aobj
;
1666 jsval fval
, *sp
, *oldsp
;
1669 JSBool arraylike
, ok
;
1675 /* Will get globalObject as 'this' and no other arguments. */
1676 return fun_call(cx
, argc
, vp
);
1679 obj
= JSVAL_TO_OBJECT(vp
[1]);
1680 if (!OBJ_DEFAULT_VALUE(cx
, obj
, JSTYPE_FUNCTION
, &vp
[1]))
1684 if (!VALUE_IS_FUNCTION(cx
, fval
)) {
1685 str
= JS_ValueToString(cx
, fval
);
1687 const char *bytes
= js_GetStringBytes(cx
, str
);
1690 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1691 JSMSG_INCOMPATIBLE_PROTO
,
1692 js_Function_str
, "apply",
1699 /* Quell GCC overwarnings. */
1704 /* If the 2nd arg is null or void, call the function with 0 args. */
1705 if (JSVAL_IS_NULL(vp
[3]) || JSVAL_IS_VOID(vp
[3])) {
1708 /* The second arg must be an array (or arguments object). */
1709 arraylike
= JS_FALSE
;
1710 if (!JSVAL_IS_PRIMITIVE(vp
[3])) {
1711 aobj
= JSVAL_TO_OBJECT(vp
[3]);
1712 if (!js_IsArrayLike(cx
, aobj
, &arraylike
, &length
))
1716 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1717 JSMSG_BAD_APPLY_ARGS
, "apply");
1723 /* Convert the first arg to 'this' and skip over it. */
1724 if (!JSVAL_IS_PRIMITIVE(vp
[2]))
1725 obj
= JSVAL_TO_OBJECT(vp
[2]);
1726 else if (!js_ValueToObject(cx
, vp
[2], &obj
))
1729 /* Allocate stack space for fval, obj, and the args. */
1730 argc
= (uintN
)JS_MIN(length
, ARRAY_INIT_LIMIT
- 1);
1731 sp
= js_AllocStack(cx
, 2 + argc
, &mark
);
1735 /* Push fval, obj, and aobj's elements as args. */
1737 *sp
++ = OBJECT_TO_JSVAL(obj
);
1738 for (i
= 0; i
< argc
; i
++) {
1739 ok
= JS_GetElement(cx
, aobj
, (jsint
)i
, sp
);
1745 /* Lift current frame to include the args and do the call. */
1749 ok
= js_Invoke(cx
, argc
,
1750 (fp
->flags
& JSFRAME_IN_FAST_CALL
)
1752 : JSINVOKE_INTERNAL
| JSINVOKE_SKIP_CALLER
);
1754 /* Store rval and pop stack back to our frame's sp. */
1758 js_FreeStack(cx
, mark
);
1764 fun_applyConstructor(JSContext
*cx
, uintN argc
, jsval
*vp
)
1769 jsval
*sp
, *newsp
, *oldsp
;
1773 if (JSVAL_IS_PRIMITIVE(vp
[2]) ||
1774 (aobj
= JSVAL_TO_OBJECT(vp
[2]),
1775 OBJ_GET_CLASS(cx
, aobj
) != &js_ArrayClass
&&
1776 OBJ_GET_CLASS(cx
, aobj
) != &js_ArgumentsClass
)) {
1777 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1778 JSMSG_BAD_APPLY_ARGS
, "__applyConstruct__");
1782 if (!js_GetLengthProperty(cx
, aobj
, &length
))
1785 if (length
>= ARRAY_INIT_LIMIT
)
1786 length
= ARRAY_INIT_LIMIT
- 1;
1787 newsp
= sp
= js_AllocStack(cx
, 2 + length
, &mark
);
1794 *sp
++ = JSVAL_NULL
; /* This is filled automagically. */
1795 for (i
= 0; i
< length
; i
++) {
1796 ok
= JS_GetElement(cx
, aobj
, (jsint
)i
, sp
);
1804 ok
= js_InvokeConstructor(cx
, newsp
, length
);
1809 js_FreeStack(cx
, mark
);
1814 static JSFunctionSpec function_methods
[] = {
1816 JS_FN(js_toSource_str
, fun_toSource
, 0,0,0,0),
1818 JS_FN(js_toString_str
, fun_toString
, 0,0,0,0),
1819 JS_FN("apply", fun_apply
, 0,2,0,0),
1820 JS_FN(call_str
, fun_call
, 0,1,0,0),
1822 JS_FN("__applyConstructor__", fun_applyConstructor
, 0,1,0,0),
1828 Function(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1830 JSStackFrame
*fp
, *caller
;
1833 uintN i
, n
, lineno
, dupflag
;
1835 const char *filename
;
1838 JSScopeProperty
*sprop
;
1839 JSString
*str
, *arg
;
1842 JSPrincipals
*principals
;
1843 jschar
*collected_args
, *cp
;
1844 size_t arg_length
, args_length
, old_args_length
;
1849 if (!(fp
->flags
& JSFRAME_CONSTRUCTING
)) {
1850 obj
= js_NewObject(cx
, &js_FunctionClass
, NULL
, NULL
);
1853 *rval
= OBJECT_TO_JSVAL(obj
);
1855 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
1860 * NB: (new Function) is not lexically closed by its caller, it's just an
1861 * anonymous function in the top-level scope that its constructor inhabits.
1862 * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
1863 * and so would a call to f from another top-level's script or function.
1865 * In older versions, before call objects, a new Function was adopted by
1866 * its running context's globalObject, which might be different from the
1867 * top-level reachable from scopeChain (in HTML frames, e.g.).
1869 parent
= OBJ_GET_PARENT(cx
, JSVAL_TO_OBJECT(argv
[-2]));
1871 fun
= js_NewFunction(cx
, obj
, NULL
, 0, JSFUN_LAMBDA
, parent
,
1872 cx
->runtime
->atomState
.anonymousAtom
);
1878 * Function is static and not called directly by other functions in this
1879 * file, therefore it is callable only as a native function by js_Invoke.
1880 * Find the scripted caller, possibly skipping other native frames such as
1881 * are built for Function.prototype.call or .apply activations that invoke
1882 * Function indirectly from a script.
1884 JS_ASSERT(!fp
->script
&& fp
->fun
&& fp
->fun
->u
.n
.native
== Function
);
1885 caller
= JS_GetScriptedCaller(cx
, fp
);
1887 filename
= caller
->script
->filename
;
1888 lineno
= js_PCToLineNumber(cx
, caller
->script
, caller
->pc
);
1889 principals
= JS_EvalFramePrincipals(cx
, fp
, caller
);
1896 /* Belt-and-braces: check that the caller has access to parent. */
1897 if (!js_CheckPrincipalsAccess(cx
, parent
, principals
,
1898 CLASS_ATOM(cx
, Function
))) {
1902 n
= argc
? argc
- 1 : 0;
1905 * Collect the function-argument arguments into one string, separated
1906 * by commas, then make a tokenstream from that string, and scan it to
1907 * get the arguments. We need to throw the full scanner at the
1908 * problem, because the argument string can legitimately contain
1909 * comments and linefeeds. XXX It might be better to concatenate
1910 * everything up into a function definition and pass it to the
1911 * compiler, but doing it this way is less of a delta from the old
1912 * code. See ECMA 15.3.2.1.
1915 for (i
= 0; i
< n
; i
++) {
1916 /* Collect the lengths for all the function-argument arguments. */
1917 arg
= js_ValueToString(cx
, argv
[i
]);
1920 argv
[i
] = STRING_TO_JSVAL(arg
);
1923 * Check for overflow. The < test works because the maximum
1924 * JSString length fits in 2 fewer bits than size_t has.
1926 old_args_length
= args_length
;
1927 args_length
= old_args_length
+ JSSTRING_LENGTH(arg
);
1928 if (args_length
< old_args_length
) {
1929 JS_ReportOutOfMemory(cx
);
1934 /* Add 1 for each joining comma and check for overflow (two ways). */
1935 old_args_length
= args_length
;
1936 args_length
= old_args_length
+ n
- 1;
1937 if (args_length
< old_args_length
||
1938 args_length
>= ~(size_t)0 / sizeof(jschar
)) {
1939 JS_ReportOutOfMemory(cx
);
1944 * Allocate a string to hold the concatenated arguments, including room
1945 * for a terminating 0. Mark cx->tempPool for later release, to free
1946 * collected_args and its tokenstream in one swoop.
1948 mark
= JS_ARENA_MARK(&cx
->tempPool
);
1949 JS_ARENA_ALLOCATE_CAST(cp
, jschar
*, &cx
->tempPool
,
1950 (args_length
+1) * sizeof(jschar
));
1952 JS_ReportOutOfMemory(cx
);
1955 collected_args
= cp
;
1958 * Concatenate the arguments into the new string, separated by commas.
1960 for (i
= 0; i
< n
; i
++) {
1961 arg
= JSVAL_TO_STRING(argv
[i
]);
1962 arg_length
= JSSTRING_LENGTH(arg
);
1963 (void) js_strncpy(cp
, JSSTRING_CHARS(arg
), arg_length
);
1966 /* Add separating comma or terminating 0. */
1967 *cp
++ = (i
+ 1 < n
) ? ',' : 0;
1971 * Make a tokenstream (allocated from cx->tempPool) that reads from
1974 ts
= js_NewTokenStream(cx
, collected_args
, args_length
, filename
,
1975 lineno
, principals
);
1977 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
1981 /* The argument string may be empty or contain no tokens. */
1982 tt
= js_GetToken(cx
, ts
);
1983 if (tt
!= TOK_EOF
) {
1986 * Check that it's a name. This also implicitly guards against
1987 * TOK_ERROR, which was already reported.
1993 * Get the atom corresponding to the name from the tokenstream;
1994 * we're assured at this point that it's a valid identifier.
1996 atom
= CURRENT_TOKEN(ts
).t_atom
;
1997 if (!js_LookupHiddenProperty(cx
, obj
, ATOM_TO_JSID(atom
),
2001 sprop
= (JSScopeProperty
*) prop
;
2006 const char *name
= js_AtomToPrintableString(cx
, atom
);
2009 * A duplicate parameter name. We force a duplicate
2010 * node on the SCOPE_LAST_PROP(scope) list with the
2011 * same id, distinguished by the SPROP_IS_DUPLICATE
2012 * flag, and not mapped by an entry in scope.
2014 JS_ASSERT(sprop
->getter
== js_GetArgument
);
2016 js_ReportCompileErrorNumber(cx
, ts
,
2020 JSMSG_DUPLICATE_FORMAL
,
2023 dupflag
= SPROP_IS_DUPLICATE
;
2025 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
2030 if (!js_AddHiddenProperty(cx
, fun
->object
, ATOM_TO_JSID(atom
),
2031 js_GetArgument
, js_SetArgument
,
2033 JSPROP_PERMANENT
| JSPROP_SHARED
,
2034 dupflag
| SPROP_HAS_SHORTID
,
2038 if (fun
->nargs
== JS_BITMASK(16)) {
2039 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2040 JSMSG_TOO_MANY_FUN_ARGS
);
2046 * Get the next token. Stop on end of stream. Otherwise
2047 * insist on a comma, get another name, and iterate.
2049 tt
= js_GetToken(cx
, ts
);
2052 if (tt
!= TOK_COMMA
)
2054 tt
= js_GetToken(cx
, ts
);
2059 ok
= js_CloseTokenStream(cx
, ts
);
2060 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2066 str
= js_ValueToString(cx
, argv
[argc
-1]);
2069 argv
[argc
-1] = STRING_TO_JSVAL(str
);
2071 str
= cx
->runtime
->emptyString
;
2074 mark
= JS_ARENA_MARK(&cx
->tempPool
);
2075 ts
= js_NewTokenStream(cx
, JSSTRING_CHARS(str
), JSSTRING_LENGTH(str
),
2076 filename
, lineno
, principals
);
2080 ok
= js_CompileFunctionBody(cx
, ts
, fun
) &&
2081 js_CloseTokenStream(cx
, ts
);
2083 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2088 * Report "malformed formal parameter" iff no illegal char or similar
2089 * scanner error was already reported.
2091 if (!(ts
->flags
& TSF_ERROR
))
2092 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_FORMAL
);
2096 * Clean up the arguments string and tokenstream if we failed to parse
2099 (void)js_CloseTokenStream(cx
, ts
);
2100 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2105 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
)
2111 proto
= JS_InitClass(cx
, obj
, NULL
, &js_FunctionClass
, Function
, 1,
2112 function_props
, function_methods
, NULL
, NULL
);
2115 atom
= js_Atomize(cx
, js_FunctionClass
.name
, strlen(js_FunctionClass
.name
),
2119 fun
= js_NewFunction(cx
, proto
, NULL
, 0, 0, obj
, NULL
);
2122 fun
->u
.i
.script
= js_NewScript(cx
, 1, 0, 0, 0, 0, 0);
2123 if (!fun
->u
.i
.script
)
2125 fun
->u
.i
.script
->code
[0] = JSOP_STOP
;
2126 fun
->flags
|= JSFUN_INTERPRETED
;
2130 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
2135 js_InitCallClass(JSContext
*cx
, JSObject
*obj
)
2139 proto
= JS_InitClass(cx
, obj
, NULL
, &js_CallClass
, NULL
, 0,
2140 NULL
, NULL
, NULL
, NULL
);
2145 * Null Call.prototype's proto slot so that Object.prototype.* does not
2146 * pollute the scope of heavyweight functions.
2148 OBJ_SET_PROTO(cx
, proto
, NULL
);
2153 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, JSNative native
, uintN nargs
,
2154 uintN flags
, JSObject
*parent
, JSAtom
*atom
)
2157 JSTempValueRooter tvr
;
2159 /* If funobj is null, allocate an object for it. */
2161 OBJ_SET_PARENT(cx
, funobj
, parent
);
2163 funobj
= js_NewObject(cx
, &js_FunctionClass
, NULL
, parent
);
2168 /* Protect fun from any potential GC callback. */
2169 JS_PUSH_SINGLE_TEMP_ROOT(cx
, OBJECT_TO_JSVAL(funobj
), &tvr
);
2172 * Allocate fun after allocating funobj so allocations in js_NewObject
2173 * and hooks called from it do not wipe out fun from newborn[GCX_FUNCTION].
2175 fun
= (JSFunction
*) js_NewGCThing(cx
, GCX_FUNCTION
, sizeof(JSFunction
));
2179 /* Initialize all function members. */
2182 fun
->flags
= flags
& JSFUN_FLAGS_MASK
;
2183 fun
->u
.n
.native
= native
;
2185 fun
->u
.n
.minargs
= 0;
2189 /* Link fun to funobj and vice versa. */
2190 if (!js_LinkFunctionObject(cx
, fun
, funobj
)) {
2191 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
2196 JS_POP_TEMP_ROOT(cx
, &tvr
);
2201 js_FinalizeFunction(JSContext
*cx
, JSFunction
*fun
)
2206 * Null-check of i.script is required since the parser sets interpreted
2209 if (FUN_INTERPRETED(fun
) && fun
->u
.i
.script
) {
2210 script
= fun
->u
.i
.script
;
2211 fun
->u
.i
.script
= NULL
;
2212 js_DestroyScript(cx
, script
);
2217 js_CloneFunctionObject(JSContext
*cx
, JSObject
*funobj
, JSObject
*parent
)
2219 JSObject
*newfunobj
;
2222 JS_ASSERT(OBJ_GET_CLASS(cx
, funobj
) == &js_FunctionClass
);
2223 newfunobj
= js_NewObject(cx
, &js_FunctionClass
, NULL
, parent
);
2226 fun
= (JSFunction
*) JS_GetPrivate(cx
, funobj
);
2227 if (!js_LinkFunctionObject(cx
, fun
, newfunobj
)) {
2228 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
2235 js_LinkFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*funobj
)
2238 fun
->object
= funobj
;
2239 return JS_SetPrivate(cx
, funobj
, fun
);
2243 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
, JSNative native
,
2244 uintN nargs
, uintN attrs
)
2248 fun
= js_NewFunction(cx
, NULL
, native
, nargs
, attrs
, obj
, atom
);
2251 if (!OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
),
2252 OBJECT_TO_JSVAL(fun
->object
),
2254 attrs
& ~JSFUN_FLAGS_MASK
, NULL
)) {
2260 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2261 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2265 js_ValueToFunction(JSContext
*cx
, jsval
*vp
, uintN flags
)
2272 if (JSVAL_IS_OBJECT(v
)) {
2273 obj
= JSVAL_TO_OBJECT(v
);
2274 if (obj
&& OBJ_GET_CLASS(cx
, obj
) != &js_FunctionClass
) {
2275 if (!OBJ_DEFAULT_VALUE(cx
, obj
, JSTYPE_FUNCTION
, &v
))
2277 obj
= VALUE_IS_FUNCTION(cx
, v
) ? JSVAL_TO_OBJECT(v
) : NULL
;
2281 js_ReportIsNotFunction(cx
, vp
, flags
);
2284 return (JSFunction
*) JS_GetPrivate(cx
, obj
);
2288 js_ValueToFunctionObject(JSContext
*cx
, jsval
*vp
, uintN flags
)
2292 JSStackFrame
*caller
;
2293 JSPrincipals
*principals
;
2295 if (VALUE_IS_FUNCTION(cx
, *vp
))
2296 return JSVAL_TO_OBJECT(*vp
);
2298 fun
= js_ValueToFunction(cx
, vp
, flags
);
2301 funobj
= fun
->object
;
2302 *vp
= OBJECT_TO_JSVAL(funobj
);
2304 caller
= JS_GetScriptedCaller(cx
, cx
->fp
);
2306 principals
= caller
->script
->principals
;
2308 /* No scripted caller, don't allow access. */
2312 if (!js_CheckPrincipalsAccess(cx
, funobj
, principals
,
2315 : cx
->runtime
->atomState
.anonymousAtom
)) {
2322 js_ValueToCallableObject(JSContext
*cx
, jsval
*vp
, uintN flags
)
2326 callable
= JSVAL_IS_PRIMITIVE(*vp
) ? NULL
: JSVAL_TO_OBJECT(*vp
);
2328 ((callable
->map
->ops
== &js_ObjectOps
)
2329 ? OBJ_GET_CLASS(cx
, callable
)->call
2330 : callable
->map
->ops
->call
)) {
2331 *vp
= OBJECT_TO_JSVAL(callable
);
2333 callable
= js_ValueToFunctionObject(cx
, vp
, flags
);
2339 js_ReportIsNotFunction(JSContext
*cx
, jsval
*vp
, uintN flags
)
2343 const char *name
, *source
;
2345 for (fp
= cx
->fp
; fp
&& !fp
->spbase
; fp
= fp
->down
)
2349 if (flags
& JSV2F_ITERATOR
) {
2350 error
= JSMSG_BAD_ITERATOR
;
2351 name
= js_iterator_str
;
2352 source
= js_ValueToPrintableSource(cx
, *vp
);
2355 } else if (flags
& JSV2F_CONSTRUCT
) {
2356 error
= JSMSG_NOT_CONSTRUCTOR
;
2358 error
= JSMSG_NOT_FUNCTION
;
2361 js_ReportValueError3(cx
, error
,
2363 !(fp
->flags
& JSFRAME_IN_FAST_CALL
) &&
2364 fp
->spbase
<= vp
&& vp
< fp
->sp
)
2366 : (flags
& JSV2F_SEARCH_STACK
)
2367 ? JSDVG_SEARCH_STACK
2368 : JSDVG_IGNORE_STACK
,