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"
71 #include "jsstaticcheck.h"
79 # include "jsxdrapi.h"
82 #include "jsatominlines.h"
83 #include "jsobjinlines.h"
88 SetArgsPrivateNative(JSObject
*argsobj
, ArgsPrivateNative
*apn
)
90 JS_ASSERT(argsobj
->isArguments());
91 uintptr_t p
= (uintptr_t) apn
;
92 argsobj
->setPrivate((void*) (p
| 2));
96 js_GetArgsValue(JSContext
*cx
, JSStackFrame
*fp
, jsval
*vp
)
100 if (fp
->flags
& JSFRAME_OVERRIDE_ARGS
) {
101 JS_ASSERT(fp
->callobj
);
102 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
103 return fp
->callobj
->getProperty(cx
, id
, vp
);
105 argsobj
= js_GetArgsObject(cx
, fp
);
108 *vp
= OBJECT_TO_JSVAL(argsobj
);
113 js_GetArgsProperty(JSContext
*cx
, JSStackFrame
*fp
, jsid id
, jsval
*vp
)
115 if (fp
->flags
& JSFRAME_OVERRIDE_ARGS
) {
116 JS_ASSERT(fp
->callobj
);
118 jsid argumentsid
= ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
);
120 if (!fp
->callobj
->getProperty(cx
, argumentsid
, &v
))
124 if (JSVAL_IS_PRIMITIVE(v
)) {
125 obj
= js_ValueToNonNullObject(cx
, v
);
129 obj
= JSVAL_TO_OBJECT(v
);
131 return obj
->getProperty(cx
, id
, vp
);
135 if (JSID_IS_INT(id
)) {
136 uint32 arg
= uint32(JSID_TO_INT(id
));
137 JSObject
*argsobj
= JSVAL_TO_OBJECT(fp
->argsobj
);
138 if (arg
< fp
->argc
) {
140 jsval v
= argsobj
->getArgsElement(arg
);
142 return argsobj
->getProperty(cx
, id
, vp
);
147 * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
148 * storage between the formal parameter and arguments[k] for all
149 * fp->argc <= k && k < fp->fun->nargs. For example, in
151 * function f(x) { x = 42; return arguments[0]; }
154 * the call to f should return undefined, not 42. If fp->argsobj
155 * is null at this point, as it would be in the example, return
159 return argsobj
->getProperty(cx
, id
, vp
);
161 } else if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)) {
162 JSObject
*argsobj
= JSVAL_TO_OBJECT(fp
->argsobj
);
163 if (argsobj
&& argsobj
->isArgsLengthOverridden())
164 return argsobj
->getProperty(cx
, id
, vp
);
165 *vp
= INT_TO_JSVAL(jsint(fp
->argc
));
171 NewArguments(JSContext
*cx
, JSObject
*parent
, uint32 argc
, JSObject
*callee
)
174 if (!js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
))
177 JSObject
*argsobj
= js_NewGCObject(cx
);
181 /* Init immediately to avoid GC seeing a half-init'ed object. */
182 argsobj
->init(&js_ArgumentsClass
, proto
, parent
, JSVAL_NULL
);
183 argsobj
->setArgsCallee(OBJECT_TO_JSVAL(callee
));
184 argsobj
->setArgsLength(argc
);
186 argsobj
->map
= cx
->runtime
->emptyArgumentsScope
;
187 cx
->runtime
->emptyArgumentsScope
->hold();
189 /* This must come after argsobj->map has been set. */
190 if (!js_EnsureReservedSlots(cx
, argsobj
, argc
))
196 PutArguments(JSContext
*cx
, JSObject
*argsobj
, jsval
*args
)
198 uint32 argc
= argsobj
->getArgsLength();
199 for (uint32 i
= 0; i
!= argc
; ++i
) {
200 jsval v
= argsobj
->getArgsElement(i
);
202 argsobj
->setArgsElement(i
, args
[i
]);
207 js_GetArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
210 * We must be in a function activation; the function must be lightweight
211 * or else fp must have a variable object.
214 JS_ASSERT_IF(fp
->fun
->flags
& JSFUN_HEAVYWEIGHT
,
215 fp
->varobj(cx
->containingCallStack(fp
)));
217 /* Skip eval and debugger frames. */
218 while (fp
->flags
& JSFRAME_SPECIAL
)
221 /* Create an arguments object for fp only if it lacks one. */
222 JSObject
*argsobj
= JSVAL_TO_OBJECT(fp
->argsobj
);
227 * Give arguments an intrinsic scope chain link to fp's global object.
228 * Since the arguments object lacks a prototype because js_ArgumentsClass
229 * is not initialized, NewObject won't assign a default parent to it.
231 * Therefore if arguments is used as the head of an eval scope chain (via
232 * a direct or indirect call to eval(program, arguments)), any reference
233 * to a standard class object in the program will fail to resolve due to
234 * js_GetClassPrototype not being able to find a global object containing
235 * the standard prototype by starting from arguments and following parent.
237 JSObject
*global
= fp
->scopeChain
;
238 while (JSObject
*parent
= global
->getParent())
242 argsobj
= NewArguments(cx
, global
, fp
->argc
, JSVAL_TO_OBJECT(fp
->argv
[-2]));
246 /* Link the new object to fp so it can get actual argument values. */
247 argsobj
->setPrivate(fp
);
248 fp
->argsobj
= OBJECT_TO_JSVAL(argsobj
);
253 js_PutArgsObject(JSContext
*cx
, JSStackFrame
*fp
)
255 JSObject
*argsobj
= JSVAL_TO_OBJECT(fp
->argsobj
);
256 JS_ASSERT(argsobj
->getPrivate() == fp
);
257 PutArguments(cx
, argsobj
, fp
->argv
);
258 argsobj
->setPrivate(NULL
);
259 fp
->argsobj
= JSVAL_NULL
;
263 * Traced versions of js_GetArgsObject and js_PutArgsObject.
267 JSObject
* JS_FASTCALL
268 js_Arguments(JSContext
*cx
, JSObject
*parent
, uint32 argc
, JSObject
*callee
,
269 double *argv
, ArgsPrivateNative
*apn
)
271 JSObject
*argsobj
= NewArguments(cx
, parent
, argc
, callee
);
275 SetArgsPrivateNative(argsobj
, apn
);
280 JS_DEFINE_CALLINFO_6(extern, OBJECT
, js_Arguments
, CONTEXT
, OBJECT
, UINT32
, OBJECT
,
281 DOUBLEPTR
, APNPTR
, 0, nanojit::ACC_STORE_ANY
)
283 /* FIXME change the return type to void. */
285 js_PutArguments(JSContext
*cx
, JSObject
*argsobj
, jsval
*args
)
287 JS_ASSERT(GetArgsPrivateNative(argsobj
));
288 PutArguments(cx
, argsobj
, args
);
289 argsobj
->setPrivate(NULL
);
293 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_PutArguments
, CONTEXT
, OBJECT
, JSVALPTR
, 0,
294 nanojit::ACC_STORE_ANY
)
297 args_delProperty(JSContext
*cx
, JSObject
*obj
, jsval idval
, jsval
*vp
)
299 JS_ASSERT(obj
->isArguments());
301 if (JSVAL_IS_INT(idval
)) {
302 uintN arg
= uintN(JSVAL_TO_INT(idval
));
303 if (arg
< obj
->getArgsLength())
304 obj
->setArgsElement(arg
, JSVAL_HOLE
);
305 } else if (idval
== ATOM_KEY(cx
->runtime
->atomState
.lengthAtom
)) {
306 obj
->setArgsLengthOverridden();
307 } else if (idval
== ATOM_KEY(cx
->runtime
->atomState
.calleeAtom
)) {
308 obj
->setArgsCallee(JSVAL_HOLE
);
313 static JS_REQUIRES_STACK JSObject
*
314 WrapEscapingClosure(JSContext
*cx
, JSStackFrame
*fp
, JSObject
*funobj
, JSFunction
*fun
)
316 JS_ASSERT(GET_FUNCTION_PRIVATE(cx
, funobj
) == fun
);
317 JS_ASSERT(fun
->optimizedClosure());
318 JS_ASSERT(!fun
->u
.i
.wrapper
);
321 * We do not attempt to reify Call and Block objects on demand for outer
322 * scopes. This could be done (see the "v8" patch in bug 494235) but it is
323 * fragile in the face of ongoing compile-time optimization. Instead, the
324 * _DBG* opcodes used by wrappers created here must cope with unresolved
325 * upvars and throw them as reference errors. Caveat debuggers!
327 JSObject
*scopeChain
= js_GetScopeChain(cx
, fp
);
331 JSObject
*wfunobj
= NewObjectWithGivenProto(cx
, &js_FunctionClass
,
335 AutoValueRooter
tvr(cx
, wfunobj
);
337 JSFunction
*wfun
= (JSFunction
*) wfunobj
;
338 wfunobj
->setPrivate(wfun
);
340 wfun
->flags
= fun
->flags
| JSFUN_HEAVYWEIGHT
;
342 wfun
->u
.i
.nupvars
= 0;
343 wfun
->u
.i
.skipmin
= fun
->u
.i
.skipmin
;
344 wfun
->u
.i
.wrapper
= true;
345 wfun
->u
.i
.script
= NULL
;
346 wfun
->u
.i
.names
.taggedAtom
= NULL
;
347 wfun
->atom
= fun
->atom
;
349 if (fun
->hasLocalNames()) {
350 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
351 jsuword
*names
= js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
356 for (uintN i
= 0, n
= fun
->countLocalNames(); i
!= n
; i
++) {
357 jsuword name
= names
[i
];
358 JSAtom
*atom
= JS_LOCAL_NAME_TO_ATOM(name
);
359 JSLocalKind localKind
= (i
< fun
->nargs
)
361 : (i
< fun
->countArgsAndVars())
362 ? (JS_LOCAL_NAME_IS_CONST(name
)
367 ok
= js_AddLocal(cx
, wfun
, atom
, localKind
);
372 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
375 JS_ASSERT(wfun
->nargs
== fun
->nargs
);
376 JS_ASSERT(wfun
->u
.i
.nvars
== fun
->u
.i
.nvars
);
377 JS_ASSERT(wfun
->u
.i
.nupvars
== fun
->u
.i
.nupvars
);
378 js_FreezeLocalNames(cx
, wfun
);
381 JSScript
*script
= fun
->u
.i
.script
;
382 jssrcnote
*snbase
= script
->notes();
383 jssrcnote
*sn
= snbase
;
384 while (!SN_IS_TERMINATOR(sn
))
386 uintN nsrcnotes
= (sn
- snbase
) + 1;
388 /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
389 JSScript
*wscript
= js_NewScript(cx
, script
->length
, nsrcnotes
,
390 script
->atomMap
.length
,
391 (script
->objectsOffset
!= 0)
392 ? script
->objects()->length
395 (script
->regexpsOffset
!= 0)
396 ? script
->regexps()->length
398 (script
->trynotesOffset
!= 0)
399 ? script
->trynotes()->length
404 memcpy(wscript
->code
, script
->code
, script
->length
);
405 wscript
->main
= wscript
->code
+ (script
->main
- script
->code
);
407 memcpy(wscript
->notes(), snbase
, nsrcnotes
* sizeof(jssrcnote
));
408 memcpy(wscript
->atomMap
.vector
, script
->atomMap
.vector
,
409 wscript
->atomMap
.length
* sizeof(JSAtom
*));
410 if (script
->objectsOffset
!= 0) {
411 memcpy(wscript
->objects()->vector
, script
->objects()->vector
,
412 wscript
->objects()->length
* sizeof(JSObject
*));
414 if (script
->regexpsOffset
!= 0) {
415 memcpy(wscript
->regexps()->vector
, script
->regexps()->vector
,
416 wscript
->regexps()->length
* sizeof(JSObject
*));
418 if (script
->trynotesOffset
!= 0) {
419 memcpy(wscript
->trynotes()->vector
, script
->trynotes()->vector
,
420 wscript
->trynotes()->length
* sizeof(JSTryNote
));
423 if (wfun
->u
.i
.nupvars
!= 0) {
424 JS_ASSERT(wfun
->u
.i
.nupvars
== wscript
->upvars()->length
);
425 memcpy(wscript
->upvars()->vector
, script
->upvars()->vector
,
426 wfun
->u
.i
.nupvars
* sizeof(uint32
));
429 jsbytecode
*pc
= wscript
->code
;
430 while (*pc
!= JSOP_STOP
) {
431 /* XYZZYbe should copy JSOP_TRAP? */
432 JSOp op
= js_GetOpcode(cx
, wscript
, pc
);
433 const JSCodeSpec
*cs
= &js_CodeSpec
[op
];
434 ptrdiff_t oplen
= cs
->length
;
436 oplen
= js_GetVariableBytecodeLength(pc
);
439 * Rewrite JSOP_{GET,CALL}DSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
440 * case where fun is an escaping flat closure. This works because the
441 * UPVAR and DSLOT ops by design have the same format: an upvar index
445 case JSOP_GETUPVAR
: *pc
= JSOP_GETUPVAR_DBG
; break;
446 case JSOP_CALLUPVAR
: *pc
= JSOP_CALLUPVAR_DBG
; break;
447 case JSOP_GETDSLOT
: *pc
= JSOP_GETUPVAR_DBG
; break;
448 case JSOP_CALLDSLOT
: *pc
= JSOP_CALLUPVAR_DBG
; break;
449 case JSOP_DEFFUN_FC
: *pc
= JSOP_DEFFUN_DBGFC
; break;
450 case JSOP_DEFLOCALFUN_FC
: *pc
= JSOP_DEFLOCALFUN_DBGFC
; break;
451 case JSOP_LAMBDA_FC
: *pc
= JSOP_LAMBDA_DBGFC
; break;
458 * Fill in the rest of wscript. This means if you add members to JSScript
459 * you must update this code. FIXME: factor into JSScript::clone method.
461 wscript
->noScriptRval
= script
->noScriptRval
;
462 wscript
->savedCallerFun
= script
->savedCallerFun
;
463 wscript
->hasSharps
= script
->hasSharps
;
464 wscript
->strictModeCode
= script
->strictModeCode
;
465 wscript
->version
= script
->version
;
466 wscript
->nfixed
= script
->nfixed
;
467 wscript
->filename
= script
->filename
;
468 wscript
->lineno
= script
->lineno
;
469 wscript
->nslots
= script
->nslots
;
470 wscript
->staticLevel
= script
->staticLevel
;
471 wscript
->principals
= script
->principals
;
472 if (wscript
->principals
)
473 JSPRINCIPALS_HOLD(cx
, wscript
->principals
);
474 #ifdef CHECK_SCRIPT_OWNER
475 wscript
->owner
= script
->owner
;
478 /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
479 FUN_SET_KIND(wfun
, JSFUN_INTERPRETED
);
480 wfun
->u
.i
.script
= wscript
;
485 ArgGetter(JSContext
*cx
, JSObject
*obj
, jsval idval
, jsval
*vp
)
487 if (!JS_InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
490 if (JSVAL_IS_INT(idval
)) {
492 * arg can exceed the number of arguments if a script changed the
493 * prototype to point to another Arguments object with a bigger argc.
495 uintN arg
= uintN(JSVAL_TO_INT(idval
));
496 if (arg
< obj
->getArgsLength()) {
498 ArgsPrivateNative
*argp
= GetArgsPrivateNative(obj
);
500 if (NativeToValue(cx
, *vp
, argp
->typemap()[arg
], &argp
->argv
[arg
]))
507 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
511 jsval v
= obj
->getArgsElement(arg
);
516 } else if (idval
== ATOM_KEY(cx
->runtime
->atomState
.lengthAtom
)) {
517 if (!obj
->isArgsLengthOverridden())
518 *vp
= INT_TO_JSVAL(obj
->getArgsLength());
520 JS_ASSERT(idval
== ATOM_KEY(cx
->runtime
->atomState
.calleeAtom
));
521 jsval v
= obj
->getArgsCallee();
522 if (v
!= JSVAL_HOLE
) {
524 * If this function or one in it needs upvars that reach above it
525 * in the scope chain, it must not be a null closure (it could be a
526 * flat closure, or an unoptimized closure -- the latter itself not
527 * necessarily heavyweight). Rather than wrap here, we simply throw
528 * to reduce code size and tell debugger users the truth instead of
529 * passing off a fibbing wrapper.
531 if (GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(v
))->needsWrapper()) {
532 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
533 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
543 ArgSetter(JSContext
*cx
, JSObject
*obj
, jsval idval
, jsval
*vp
)
546 // To be able to set a property here on trace, we would have to make
547 // sure any updates also get written back to the trace native stack.
548 // For simplicity, we just leave trace, since this is presumably not
549 // a common operation.
550 if (JS_ON_TRACE(cx
)) {
556 if (!JS_InstanceOf(cx
, obj
, &js_ArgumentsClass
, NULL
))
559 if (JSVAL_IS_INT(idval
)) {
560 uintN arg
= uintN(JSVAL_TO_INT(idval
));
561 if (arg
< obj
->getArgsLength()) {
562 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
569 JS_ASSERT(idval
== ATOM_KEY(cx
->runtime
->atomState
.lengthAtom
) ||
570 idval
== ATOM_KEY(cx
->runtime
->atomState
.calleeAtom
));
574 * For simplicity we use delete/set to replace the property with one
575 * backed by the default Object getter and setter. Note the we rely on
576 * args_delete to clear the corresponding reserved slot so the GC can
579 JS_ASSERT_IF(JSVAL_IS_STRING(idval
), JSVAL_TO_STRING(idval
)->isAtomized());
580 jsid id
= (jsid
)idval
;
582 AutoValueRooter
tvr(cx
);
583 return js_DeleteProperty(cx
, obj
, id
, tvr
.addr()) &&
584 js_SetProperty(cx
, obj
, id
, vp
);
588 args_resolve(JSContext
*cx
, JSObject
*obj
, jsval idval
, uintN flags
,
591 JS_ASSERT(obj
->isArguments());
595 if (JSVAL_IS_INT(idval
)) {
596 uint32 arg
= uint32(JSVAL_TO_INT(idval
));
597 if (arg
< obj
->getArgsLength() && obj
->getArgsElement(arg
) != JSVAL_HOLE
)
598 id
= INT_JSVAL_TO_JSID(idval
);
599 } else if (idval
== ATOM_KEY(cx
->runtime
->atomState
.lengthAtom
)) {
600 if (!obj
->isArgsLengthOverridden())
601 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
);
602 } else if (idval
== ATOM_KEY(cx
->runtime
->atomState
.calleeAtom
)) {
603 if (obj
->getArgsCallee() != JSVAL_HOLE
)
604 id
= ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
);
609 * XXX ECMA specs DontEnum even for indexed properties, contrary to
610 * other array-like objects.
612 if (!js_DefineProperty(cx
, obj
, id
, JSVAL_VOID
, ArgGetter
, ArgSetter
, JSPROP_SHARED
))
620 args_enumerate(JSContext
*cx
, JSObject
*obj
)
622 JS_ASSERT(obj
->isArguments());
625 * Trigger reflection in args_resolve using a series of js_LookupProperty
628 int argc
= int(obj
->getArgsLength());
629 for (int i
= -2; i
!= argc
; i
++) {
631 ? ATOM_TO_JSID(cx
->runtime
->atomState
.lengthAtom
)
633 ? ATOM_TO_JSID(cx
->runtime
->atomState
.calleeAtom
)
634 : INT_JSVAL_TO_JSID(INT_TO_JSVAL(i
));
638 if (!js_LookupProperty(cx
, obj
, id
, &pobj
, &prop
))
641 /* prop is null when the property was deleted. */
643 pobj
->dropProperty(cx
, prop
);
648 #if JS_HAS_GENERATORS
650 * If a generator-iterator's arguments or call object escapes, it needs to
651 * mark its generator object.
654 args_or_call_trace(JSTracer
*trc
, JSObject
*obj
)
656 if (obj
->isArguments()) {
657 if (GetArgsPrivateNative(obj
))
660 JS_ASSERT(obj
->getClass() == &js_CallClass
);
663 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
664 if (fp
&& (fp
->flags
& JSFRAME_GENERATOR
)) {
665 JS_CALL_OBJECT_TRACER(trc
, FRAME_TO_GENERATOR(fp
)->obj
,
666 "FRAME_TO_GENERATOR(fp)->obj");
670 # define args_or_call_trace NULL
674 args_reserveSlots(JSContext
*cx
, JSObject
*obj
)
676 return obj
->getArgsLength();
680 * The Arguments class is not initialized via JS_InitClass, and must not be,
681 * because its name is "Object". Per ECMA, that causes instances of it to
682 * delegate to the object named by Object.prototype. It also ensures that
683 * arguments.toString() returns "[object Object]".
685 * The JSClass functions below collaborate to lazily reflect and synchronize
686 * actual argument values, argument count, and callee function object stored
687 * in a JSStackFrame with their corresponding property values in the frame's
690 JSClass js_ArgumentsClass
= {
692 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
|
693 JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS
) |
694 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
695 JS_PropertyStub
, args_delProperty
,
696 JS_PropertyStub
, JS_PropertyStub
,
697 args_enumerate
, (JSResolveOp
) args_resolve
,
698 JS_ConvertStub
, NULL
,
702 JS_CLASS_TRACE(args_or_call_trace
), args_reserveSlots
705 const uint32 JSSLOT_CALLEE
= JSSLOT_PRIVATE
+ 1;
706 const uint32 JSSLOT_CALL_ARGUMENTS
= JSSLOT_PRIVATE
+ 2;
707 const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS
= 2;
710 * A Declarative Environment object stores its active JSStackFrame pointer in
711 * its private slot, just as Call and Arguments objects do.
713 JSClass js_DeclEnvClass
= {
715 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
716 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
717 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, NULL
,
718 JSCLASS_NO_OPTIONAL_MEMBERS
722 CheckForEscapingClosure(JSContext
*cx
, JSObject
*obj
, jsval
*vp
)
724 JS_ASSERT(obj
->getClass() == &js_CallClass
||
725 obj
->getClass() == &js_DeclEnvClass
);
729 if (VALUE_IS_FUNCTION(cx
, v
)) {
730 JSObject
*funobj
= JSVAL_TO_OBJECT(v
);
731 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
734 * Any escaping null or flat closure that reaches above itself or
735 * contains nested functions that reach above it must be wrapped.
736 * We can wrap only when this Call or Declarative Environment obj
737 * still has an active stack frame associated with it.
739 if (fun
->needsWrapper()) {
742 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
744 JSObject
*wrapper
= WrapEscapingClosure(cx
, fp
, funobj
, fun
);
747 *vp
= OBJECT_TO_JSVAL(wrapper
);
751 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
752 JSMSG_OPTIMIZED_CLOSURE_LEAK
);
760 CalleeGetter(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
762 return CheckForEscapingClosure(cx
, obj
, vp
);
766 NewCallObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
)
768 JSObject
*callobj
= NewObjectWithGivenProto(cx
, &js_CallClass
, NULL
, scopeChain
);
770 !js_EnsureReservedSlots(cx
, callobj
, fun
->countArgsAndVars())) {
777 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
)
781 /* Create a call object for fp only if it lacks one. */
783 callobj
= fp
->callobj
;
788 /* A call object should be a frame's outermost scope chain element. */
789 JSClass
*classp
= fp
->scopeChain
->getClass();
790 if (classp
== &js_WithClass
|| classp
== &js_BlockClass
|| classp
== &js_CallClass
)
791 JS_ASSERT(fp
->scopeChain
->getPrivate() != fp
);
795 * Create the call object, using the frame's enclosing scope as its
796 * parent, and link the call to its stack frame. For a named function
797 * expression Call's parent points to an environment object holding
800 JSAtom
*lambdaName
= (fp
->fun
->flags
& JSFUN_LAMBDA
) ? fp
->fun
->atom
: NULL
;
802 JSObject
*env
= NewObjectWithGivenProto(cx
, &js_DeclEnvClass
, NULL
,
808 /* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */
809 fp
->scopeChain
= env
;
811 if (!js_DefineNativeProperty(cx
, fp
->scopeChain
, ATOM_TO_JSID(lambdaName
),
814 JSPROP_PERMANENT
| JSPROP_READONLY
,
820 callobj
= NewCallObject(cx
, fp
->fun
, fp
->scopeChain
);
824 callobj
->setPrivate(fp
);
826 JS_ASSERT(fp
->fun
== GET_FUNCTION_PRIVATE(cx
, fp
->calleeObject()));
827 callobj
->setSlot(JSSLOT_CALLEE
, fp
->calleeValue());
828 fp
->callobj
= callobj
;
831 * Push callobj on the top of the scope chain, and make it the
834 fp
->scopeChain
= callobj
;
838 JSObject
* JS_FASTCALL
839 js_CreateCallObjectOnTrace(JSContext
*cx
, JSFunction
*fun
, JSObject
*callee
, JSObject
*scopeChain
)
841 JS_ASSERT(!js_IsNamedLambda(fun
));
842 JSObject
*callobj
= NewCallObject(cx
, fun
, scopeChain
);
845 callobj
->setSlot(JSSLOT_CALLEE
, OBJECT_TO_JSVAL(callee
));
849 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CreateCallObjectOnTrace
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
,
850 0, nanojit::ACC_STORE_ANY
)
853 js_GetCallObjectFunction(JSObject
*obj
)
857 JS_ASSERT(obj
->getClass() == &js_CallClass
);
858 v
= obj
->getSlot(JSSLOT_CALLEE
);
859 if (JSVAL_IS_VOID(v
)) {
860 /* Newborn or prototype object. */
863 JS_ASSERT(!JSVAL_IS_PRIMITIVE(v
));
864 return GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(v
));
868 CopyValuesToCallObject(JSObject
*callobj
, int nargs
, jsval
*argv
, int nvars
, jsval
*slots
)
870 memcpy(callobj
->dslots
, argv
, nargs
* sizeof(jsval
));
871 memcpy(callobj
->dslots
+ nargs
, slots
, nvars
* sizeof(jsval
));
875 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
)
877 JSObject
*callobj
= fp
->callobj
;
880 /* Get the arguments object to snapshot fp's actual argument values. */
882 if (!(fp
->flags
& JSFRAME_OVERRIDE_ARGS
))
883 callobj
->setSlot(JSSLOT_CALL_ARGUMENTS
, fp
->argsobj
);
884 js_PutArgsObject(cx
, fp
);
887 JSFunction
*fun
= fp
->fun
;
888 JS_ASSERT(fun
== js_GetCallObjectFunction(callobj
));
889 uintN n
= fun
->countArgsAndVars();
892 * Since for a call object all fixed slots happen to be taken, we can copy
893 * arguments and variables straight into JSObject.dslots.
895 JS_STATIC_ASSERT(JS_INITIAL_NSLOTS
- JSSLOT_PRIVATE
==
896 1 + CALL_CLASS_FIXED_RESERVED_SLOTS
);
898 JS_ASSERT(callobj
->numSlots() >= JS_INITIAL_NSLOTS
+ n
);
899 n
+= JS_INITIAL_NSLOTS
;
900 CopyValuesToCallObject(callobj
, fun
->nargs
, fp
->argv
, fun
->u
.i
.nvars
, fp
->slots
);
903 /* Clear private pointers to fp, which is about to go away (js_Invoke). */
904 if (js_IsNamedLambda(fun
)) {
905 JSObject
*env
= callobj
->getParent();
907 JS_ASSERT(env
->getClass() == &js_DeclEnvClass
);
908 JS_ASSERT(env
->getPrivate() == fp
);
909 env
->setPrivate(NULL
);
912 callobj
->setPrivate(NULL
);
917 js_PutCallObjectOnTrace(JSContext
*cx
, JSObject
*scopeChain
, uint32 nargs
, jsval
*argv
,
918 uint32 nvars
, jsval
*slots
)
920 JS_ASSERT(scopeChain
->hasClass(&js_CallClass
));
921 JS_ASSERT(!scopeChain
->getPrivate());
923 uintN n
= nargs
+ nvars
;
925 CopyValuesToCallObject(scopeChain
, nargs
, argv
, nvars
, slots
);
930 JS_DEFINE_CALLINFO_6(extern, BOOL
, js_PutCallObjectOnTrace
, CONTEXT
, OBJECT
, UINT32
, JSVALPTR
,
931 UINT32
, JSVALPTR
, 0, nanojit::ACC_STORE_ANY
)
934 call_enumerate(JSContext
*cx
, JSObject
*obj
)
945 fun
= js_GetCallObjectFunction(obj
);
946 n
= fun
? fun
->countArgsAndVars() : 0;
950 mark
= JS_ARENA_MARK(&cx
->tempPool
);
952 MUST_FLOW_THROUGH("out");
953 names
= js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
959 for (i
= 0; i
!= n
; ++i
) {
960 name
= JS_LOCAL_NAME_TO_ATOM(names
[i
]);
965 * Trigger reflection by looking up the name of the argument or
968 ok
= js_LookupProperty(cx
, obj
, ATOM_TO_JSID(name
), &pobj
, &prop
);
973 * The call object will always have a property corresponding to the
974 * argument or variable name because call_resolve creates the property
975 * using JSPROP_PERMANENT.
978 JS_ASSERT(pobj
== obj
);
979 pobj
->dropProperty(cx
, prop
);
984 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
988 enum JSCallPropertyKind
{
996 CallPropertyOp(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
,
997 JSCallPropertyKind kind
, JSBool setter
= false)
999 JS_ASSERT(obj
->getClass() == &js_CallClass
);
1002 if (kind
!= JSCPK_ARGUMENTS
) {
1003 JS_ASSERT((int16
) JSVAL_TO_INT(id
) == JSVAL_TO_INT(id
));
1004 i
= (uint16
) JSVAL_TO_INT(id
);
1008 if (kind
== JSCPK_UPVAR
) {
1009 JSObject
*callee
= JSVAL_TO_OBJECT(obj
->getSlot(JSSLOT_CALLEE
));
1012 JSFunction
*callee_fun
= (JSFunction
*) callee
->getPrivate();
1013 JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun
));
1014 JS_ASSERT(i
< callee_fun
->u
.i
.nupvars
);
1017 array
= callee
->dslots
;
1019 JSFunction
*fun
= js_GetCallObjectFunction(obj
);
1020 JS_ASSERT_IF(kind
== JSCPK_ARG
, i
< fun
->nargs
);
1021 JS_ASSERT_IF(kind
== JSCPK_VAR
, i
< fun
->u
.i
.nvars
);
1023 JSStackFrame
*fp
= (JSStackFrame
*) obj
->getPrivate();
1025 if (kind
== JSCPK_ARGUMENTS
) {
1028 fp
->flags
|= JSFRAME_OVERRIDE_ARGS
;
1029 obj
->setSlot(JSSLOT_CALL_ARGUMENTS
, *vp
);
1031 if (fp
&& !(fp
->flags
& JSFRAME_OVERRIDE_ARGS
)) {
1034 argsobj
= js_GetArgsObject(cx
, fp
);
1037 *vp
= OBJECT_TO_JSVAL(argsobj
);
1039 *vp
= obj
->getSlot(JSSLOT_CALL_ARGUMENTS
);
1046 i
+= CALL_CLASS_FIXED_RESERVED_SLOTS
;
1047 if (kind
== JSCPK_VAR
)
1050 JS_ASSERT(kind
== JSCPK_ARG
);
1052 ? JS_SetReservedSlot(cx
, obj
, i
, *vp
)
1053 : JS_GetReservedSlot(cx
, obj
, i
, vp
);
1056 if (kind
== JSCPK_ARG
) {
1059 JS_ASSERT(kind
== JSCPK_VAR
);
1065 GC_POKE(cx
, array
[i
]);
1074 GetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1076 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARGUMENTS
);
1080 SetCallArguments(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1082 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARGUMENTS
, true);
1086 js_GetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1088 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARG
);
1092 SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1094 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_ARG
, true);
1098 GetFlatUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1100 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_UPVAR
);
1104 SetFlatUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1106 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_UPVAR
, true);
1110 js_GetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1112 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
);
1116 js_GetCallVarChecked(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1118 if (!CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
))
1121 return CheckForEscapingClosure(cx
, obj
, vp
);
1125 SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
1127 return CallPropertyOp(cx
, obj
, id
, vp
, JSCPK_VAR
, true);
1131 js_SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval v
)
1133 return CallPropertyOp(cx
, obj
, id
, &v
, JSCPK_ARG
, true);
1137 js_SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval v
)
1139 return CallPropertyOp(cx
, obj
, id
, &v
, JSCPK_VAR
, true);
1142 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallArg
, CONTEXT
, OBJECT
, JSID
, JSVAL
, 0,
1143 nanojit::ACC_STORE_ANY
)
1144 JS_DEFINE_CALLINFO_4(extern, BOOL
, js_SetCallVar
, CONTEXT
, OBJECT
, JSID
, JSVAL
, 0,
1145 nanojit::ACC_STORE_ANY
)
1148 call_resolve(JSContext
*cx
, JSObject
*obj
, jsval idval
, uintN flags
,
1153 JSLocalKind localKind
;
1154 JSPropertyOp getter
, setter
;
1157 JS_ASSERT(obj
->getClass() == &js_CallClass
);
1158 JS_ASSERT(!obj
->getProto());
1160 if (!JSVAL_IS_STRING(idval
))
1163 JS_ASSERT(JSVAL_TO_STRING(idval
)->isAtomized());
1164 jsid id
= (jsval
)idval
;
1166 callee
= obj
->getSlot(JSSLOT_CALLEE
);
1167 if (JSVAL_IS_VOID(callee
))
1169 fun
= GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(callee
));
1172 * Check whether the id refers to a formal parameter, local variable or
1173 * the arguments special name.
1175 * We define all such names using JSDNP_DONT_PURGE to avoid an expensive
1176 * shape invalidation in js_DefineNativeProperty. If such an id happens to
1177 * shadow a global or upvar of the same name, any inner functions can
1178 * never access the outer binding. Thus it cannot invalidate any property
1179 * cache entries or derived trace guards for the outer binding. See also
1180 * comments in js_PurgeScopeChainHelper from jsobj.cpp.
1182 localKind
= js_LookupLocal(cx
, fun
, JSID_TO_ATOM(id
), &slot
);
1183 if (localKind
!= JSLOCAL_NONE
) {
1184 JS_ASSERT((uint16
) slot
== slot
);
1187 * We follow 10.2.3 of ECMA 262 v3 and make argument and variable
1188 * properties of the Call objects enumerable.
1190 attrs
= JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_SHARED
;
1191 if (localKind
== JSLOCAL_ARG
) {
1192 JS_ASSERT(slot
< fun
->nargs
);
1193 getter
= js_GetCallArg
;
1194 setter
= SetCallArg
;
1196 JSCallPropertyKind cpkind
;
1197 if (localKind
== JSLOCAL_UPVAR
) {
1198 if (!FUN_FLAT_CLOSURE(fun
))
1200 getter
= GetFlatUpvar
;
1201 setter
= SetFlatUpvar
;
1202 cpkind
= JSCPK_UPVAR
;
1204 JS_ASSERT(localKind
== JSLOCAL_VAR
|| localKind
== JSLOCAL_CONST
);
1205 JS_ASSERT(slot
< fun
->u
.i
.nvars
);
1206 getter
= js_GetCallVar
;
1207 setter
= SetCallVar
;
1209 if (localKind
== JSLOCAL_CONST
)
1210 attrs
|= JSPROP_READONLY
;
1214 * Use js_GetCallVarChecked if the local's value is a null closure.
1215 * This way we penalize performance only slightly on first use of a
1216 * null closure, not on every use.
1219 if (!CallPropertyOp(cx
, obj
, INT_TO_JSID((int16
)slot
), &v
, cpkind
))
1221 if (VALUE_IS_FUNCTION(cx
, v
) &&
1222 GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(v
))->needsWrapper()) {
1223 getter
= js_GetCallVarChecked
;
1226 if (!js_DefineNativeProperty(cx
, obj
, id
, JSVAL_VOID
, getter
, setter
,
1227 attrs
, JSScopeProperty::HAS_SHORTID
, (int16
) slot
,
1228 NULL
, JSDNP_DONT_PURGE
)) {
1236 * Resolve arguments so that we never store a particular Call object's
1237 * arguments object reference in a Call prototype's |arguments| slot.
1239 if (id
== ATOM_TO_JSID(cx
->runtime
->atomState
.argumentsAtom
)) {
1240 if (!js_DefineNativeProperty(cx
, obj
, id
, JSVAL_VOID
,
1241 GetCallArguments
, SetCallArguments
,
1242 JSPROP_PERMANENT
| JSPROP_SHARED
,
1243 0, 0, NULL
, JSDNP_DONT_PURGE
)) {
1250 /* Control flow reaches here only if id was not resolved. */
1255 call_reserveSlots(JSContext
*cx
, JSObject
*obj
)
1259 fun
= js_GetCallObjectFunction(obj
);
1260 return fun
->countArgsAndVars();
1263 JS_FRIEND_DATA(JSClass
) js_CallClass
= {
1265 JSCLASS_HAS_PRIVATE
|
1266 JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS
) |
1267 JSCLASS_NEW_RESOLVE
| JSCLASS_IS_ANONYMOUS
| JSCLASS_MARK_IS_TRACE
,
1268 JS_PropertyStub
, JS_PropertyStub
,
1269 JS_PropertyStub
, JS_PropertyStub
,
1270 call_enumerate
, (JSResolveOp
)call_resolve
,
1275 JS_CLASS_TRACE(args_or_call_trace
), call_reserveSlots
1278 /* Generic function tinyids. */
1280 FUN_ARGUMENTS
= -1, /* predefined arguments local variable */
1281 FUN_LENGTH
= -2, /* number of actual args, arity if inactive */
1282 FUN_ARITY
= -3, /* number of formal parameters; desired argc */
1283 FUN_NAME
= -4, /* function name, "" if anonymous */
1284 FUN_CALLER
= -5 /* Function.prototype.caller, backward compat */
1288 fun_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
1293 JSSecurityCallbacks
*callbacks
;
1295 if (!JSVAL_IS_INT(id
))
1297 slot
= JSVAL_TO_INT(id
);
1300 * Loop because getter and setter can be delegated from another class,
1301 * but loop only for FUN_LENGTH because we must pretend that f.length
1302 * is in each function instance f, per ECMA-262, instead of only in the
1303 * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
1304 * to make it appear so).
1306 * This code couples tightly to the attributes for the function_props[]
1307 * initializers above, and to js_SetProperty and js_HasOwnProperty.
1309 * It's important to allow delegating objects, even though they inherit
1310 * this getter (fun_getProperty), to override arguments, arity, caller,
1311 * and name. If we didn't return early for slot != FUN_LENGTH, we would
1312 * clobber *vp with the native property value, instead of letting script
1313 * override that value in delegating objects.
1315 * Note how that clobbering is what simulates JSPROP_READONLY for all of
1316 * the non-standard properties when the directly addressed object (obj)
1317 * is a function object (i.e., when this loop does not iterate).
1319 while (!(fun
= (JSFunction
*)
1320 JS_GetInstancePrivate(cx
, obj
, &js_FunctionClass
, NULL
))) {
1321 if (slot
!= FUN_LENGTH
)
1323 obj
= obj
->getProto();
1328 /* Find fun's top-most activation record. */
1329 for (fp
= js_GetTopStackFrame(cx
);
1330 fp
&& (fp
->fun
!= fun
|| (fp
->flags
& JSFRAME_SPECIAL
));
1337 /* Warn if strict about f.arguments or equivalent unqualified uses. */
1338 if (!JS_ReportErrorFlagsAndNumber(cx
,
1339 JSREPORT_WARNING
| JSREPORT_STRICT
,
1340 js_GetErrorMessage
, NULL
,
1341 JSMSG_DEPRECATED_USAGE
,
1342 js_arguments_str
)) {
1346 if (!js_GetArgsValue(cx
, fp
, vp
))
1355 *vp
= INT_TO_JSVAL((jsint
)fun
->nargs
);
1360 ? ATOM_KEY(fun
->atom
)
1361 : STRING_TO_JSVAL(cx
->runtime
->emptyString
);
1365 if (fp
&& fp
->down
&& fp
->down
->fun
) {
1366 JSFunction
*caller
= fp
->down
->fun
;
1368 * See equivalent condition in args_getProperty for ARGS_CALLEE,
1369 * but here we do not want to throw, since this escape can happen
1370 * via foo.caller alone, without any debugger or indirect eval. And
1371 * it seems foo.caller is still used on the Web.
1373 if (caller
->needsWrapper()) {
1374 JSObject
*wrapper
= WrapEscapingClosure(cx
, fp
->down
, FUN_OBJECT(caller
), caller
);
1377 *vp
= OBJECT_TO_JSVAL(wrapper
);
1381 JS_ASSERT(fp
->down
->argv
);
1382 *vp
= fp
->down
->calleeValue();
1386 if (!JSVAL_IS_PRIMITIVE(*vp
)) {
1387 callbacks
= JS_GetSecurityCallbacks(cx
);
1388 if (callbacks
&& callbacks
->checkObjectAccess
) {
1389 id
= ATOM_KEY(cx
->runtime
->atomState
.callerAtom
);
1390 if (!callbacks
->checkObjectAccess(cx
, obj
, id
, JSACC_READ
, vp
))
1397 /* XXX fun[0] and fun.arguments[0] are equivalent. */
1398 if (fp
&& fp
->fun
&& (uintN
)slot
< fp
->fun
->nargs
)
1399 *vp
= fp
->argv
[slot
];
1407 * ECMA-262 specifies that length is a property of function object instances,
1408 * but we can avoid that space cost by delegating to a prototype property that
1409 * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes
1410 * a fresh length value based on the arity of the individual function object's
1413 * The extensions below other than length, i.e., the ones not in ECMA-262,
1414 * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
1415 * with ECMA we must allow a delegating object to override them. Therefore to
1416 * avoid entraining garbage in Function.prototype slots, they must be resolved
1417 * in non-prototype function objects, wherefore the lazy_function_props table
1418 * and fun_resolve's use of it.
1420 #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
1422 static JSPropertySpec function_props
[] = {
1423 {js_length_str
, FUN_LENGTH
, LENGTH_PROP_ATTRS
, fun_getProperty
, JS_PropertyStub
},
1427 typedef struct LazyFunctionProp
{
1433 /* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
1434 static LazyFunctionProp lazy_function_props
[] = {
1435 {ATOM_OFFSET(arguments
), FUN_ARGUMENTS
, JSPROP_PERMANENT
},
1436 {ATOM_OFFSET(arity
), FUN_ARITY
, JSPROP_PERMANENT
},
1437 {ATOM_OFFSET(caller
), FUN_CALLER
, JSPROP_PERMANENT
},
1438 {ATOM_OFFSET(name
), FUN_NAME
, JSPROP_PERMANENT
},
1442 fun_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
1449 if (!JSVAL_IS_STRING(id
))
1452 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
1455 * No need to reflect fun.prototype in 'fun.prototype = ... '. Assert that
1456 * fun is not a compiler-created function object, which must never leak to
1457 * script or embedding code and then be mutated.
1459 if (flags
& JSRESOLVE_ASSIGNING
) {
1460 JS_ASSERT(!IsInternalFunctionObject(obj
));
1465 * Ok, check whether id is 'prototype' and bootstrap the function object's
1466 * prototype property.
1468 atom
= cx
->runtime
->atomState
.classPrototypeAtom
;
1469 if (id
== ATOM_KEY(atom
)) {
1470 JS_ASSERT(!IsInternalFunctionObject(obj
));
1473 * Beware of the wacky case of a user function named Object -- trying
1474 * to find a prototype for that will recur back here _ad perniciem_.
1476 if (fun
->atom
== CLASS_ATOM(cx
, Object
))
1480 * Make the prototype object to have the same parent as the function
1483 JSObject
*proto
= NewObject(cx
, &js_ObjectClass
, NULL
, obj
->getParent());
1488 * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1489 * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1490 * native "system" constructors such as Object or Function. So lazily
1491 * set the former here in fun_resolve, but eagerly define the latter
1492 * in JS_InitClass, with the right attributes.
1494 if (!js_SetClassPrototype(cx
, obj
, proto
, JSPROP_PERMANENT
))
1501 for (i
= 0; i
< JS_ARRAY_LENGTH(lazy_function_props
); i
++) {
1502 LazyFunctionProp
*lfp
= &lazy_function_props
[i
];
1504 atom
= OFFSET_TO_ATOM(cx
->runtime
, lfp
->atomOffset
);
1505 if (id
== ATOM_KEY(atom
)) {
1506 JS_ASSERT(!IsInternalFunctionObject(obj
));
1508 if (!js_DefineNativeProperty(cx
, obj
,
1509 ATOM_TO_JSID(atom
), JSVAL_VOID
,
1510 fun_getProperty
, JS_PropertyStub
,
1511 lfp
->attrs
, JSScopeProperty::HAS_SHORTID
,
1512 lfp
->tinyid
, NULL
)) {
1525 /* XXX store parent and proto, if defined */
1527 js_XDRFunctionObject(JSXDRState
*xdr
, JSObject
**objp
)
1531 uint32 firstword
; /* flag telling whether fun->atom is non-null,
1532 plus for fun->u.i.skipmin, fun->u.i.wrapper,
1533 and 14 bits reserved for future use */
1534 uintN nargs
, nvars
, nupvars
, n
;
1535 uint32 localsword
; /* word for argument and variable counts */
1536 uint32 flagsword
; /* word for fun->u.i.nupvars and fun->flags */
1539 if (xdr
->mode
== JSXDR_ENCODE
) {
1540 fun
= GET_FUNCTION_PRIVATE(cx
, *objp
);
1541 if (!FUN_INTERPRETED(fun
)) {
1542 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1543 JSMSG_NOT_SCRIPTED_FUNCTION
,
1544 JS_GetFunctionName(fun
));
1547 if (fun
->u
.i
.wrapper
) {
1548 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1549 JSMSG_XDR_CLOSURE_WRAPPER
,
1550 JS_GetFunctionName(fun
));
1553 JS_ASSERT((fun
->u
.i
.wrapper
& ~1U) == 0);
1554 firstword
= (fun
->u
.i
.skipmin
<< 2) | (fun
->u
.i
.wrapper
<< 1) | !!fun
->atom
;
1556 nvars
= fun
->u
.i
.nvars
;
1557 nupvars
= fun
->u
.i
.nupvars
;
1558 localsword
= (nargs
<< 16) | nvars
;
1559 flagsword
= (nupvars
<< 16) | fun
->flags
;
1561 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, JSFUN_INTERPRETED
, NULL
, NULL
);
1564 FUN_OBJECT(fun
)->clearParent();
1565 FUN_OBJECT(fun
)->clearProto();
1567 nvars
= nargs
= nupvars
= 0; /* quell GCC uninitialized warning */
1571 AutoValueRooter
tvr(cx
, FUN_OBJECT(fun
));
1573 if (!JS_XDRUint32(xdr
, &firstword
))
1575 if ((firstword
& 1U) && !js_XDRStringAtom(xdr
, &fun
->atom
))
1577 if (!JS_XDRUint32(xdr
, &localsword
) ||
1578 !JS_XDRUint32(xdr
, &flagsword
)) {
1582 if (xdr
->mode
== JSXDR_DECODE
) {
1583 nargs
= localsword
>> 16;
1584 nvars
= uint16(localsword
);
1585 JS_ASSERT((flagsword
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
);
1586 nupvars
= flagsword
>> 16;
1587 fun
->flags
= uint16(flagsword
);
1588 fun
->u
.i
.skipmin
= uint16(firstword
>> 2);
1589 fun
->u
.i
.wrapper
= JSPackedBool((firstword
>> 1) & 1);
1592 /* do arguments and local vars */
1593 n
= nargs
+ nvars
+ nupvars
;
1601 JSLocalKind localKind
;
1604 mark
= JS_ARENA_MARK(&xdr
->cx
->tempPool
);
1607 * From this point the control must flow via the label release_mark.
1609 * To xdr the names we prefix the names with a bitmap descriptor and
1610 * then xdr the names as strings. For argument names (indexes below
1611 * nargs) the corresponding bit in the bitmap is unset when the name
1612 * is null. Such null names are not encoded or decoded. For variable
1613 * names (indexes starting from nargs) bitmap's bit is set when the
1614 * name is declared as const, not as ordinary var.
1616 MUST_FLOW_THROUGH("release_mark");
1617 bitmapLength
= JS_HOWMANY(n
, JS_BITS_PER_UINT32
);
1618 JS_ARENA_ALLOCATE_CAST(bitmap
, uint32
*, &xdr
->cx
->tempPool
,
1619 bitmapLength
* sizeof *bitmap
);
1621 js_ReportOutOfScriptQuota(xdr
->cx
);
1625 if (xdr
->mode
== JSXDR_ENCODE
) {
1626 names
= js_GetLocalNameArray(xdr
->cx
, fun
, &xdr
->cx
->tempPool
);
1631 PodZero(bitmap
, bitmapLength
);
1632 for (i
= 0; i
!= n
; ++i
) {
1634 ? JS_LOCAL_NAME_TO_ATOM(names
[i
]) != NULL
1635 : JS_LOCAL_NAME_IS_CONST(names
[i
])) {
1636 bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] |=
1637 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1));
1643 names
= NULL
; /* quell GCC uninitialized warning */
1646 for (i
= 0; i
!= bitmapLength
; ++i
) {
1647 ok
= !!JS_XDRUint32(xdr
, &bitmap
[i
]);
1651 for (i
= 0; i
!= n
; ++i
) {
1653 !(bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] &
1654 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1)))) {
1655 if (xdr
->mode
== JSXDR_DECODE
) {
1656 ok
= !!js_AddLocal(xdr
->cx
, fun
, NULL
, JSLOCAL_ARG
);
1660 JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names
[i
]));
1664 if (xdr
->mode
== JSXDR_ENCODE
)
1665 name
= JS_LOCAL_NAME_TO_ATOM(names
[i
]);
1666 ok
= !!js_XDRStringAtom(xdr
, &name
);
1669 if (xdr
->mode
== JSXDR_DECODE
) {
1670 localKind
= (i
< nargs
)
1672 : (i
< nargs
+ nvars
)
1673 ? (bitmap
[i
>> JS_BITS_PER_UINT32_LOG2
] &
1674 JS_BIT(i
& (JS_BITS_PER_UINT32
- 1))
1678 ok
= !!js_AddLocal(xdr
->cx
, fun
, name
, localKind
);
1685 JS_ARENA_RELEASE(&xdr
->cx
->tempPool
, mark
);
1689 if (xdr
->mode
== JSXDR_DECODE
)
1690 js_FreezeLocalNames(cx
, fun
);
1693 if (!js_XDRScript(xdr
, &fun
->u
.i
.script
, false, NULL
))
1696 if (xdr
->mode
== JSXDR_DECODE
) {
1697 *objp
= FUN_OBJECT(fun
);
1698 if (fun
->u
.i
.script
!= JSScript::emptyScript()) {
1699 #ifdef CHECK_SCRIPT_OWNER
1700 fun
->u
.i
.script
->owner
= NULL
;
1702 js_CallNewScriptHook(cx
, fun
->u
.i
.script
, fun
);
1709 #else /* !JS_HAS_XDR */
1711 #define js_XDRFunctionObject NULL
1713 #endif /* !JS_HAS_XDR */
1716 * [[HasInstance]] internal method for Function objects: fetch the .prototype
1717 * property of its 'this' parameter, and walks the prototype chain of v (only
1718 * if v is an object) returning true if .prototype is found.
1721 fun_hasInstance(JSContext
*cx
, JSObject
*obj
, jsval v
, JSBool
*bp
)
1724 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
1725 if (!obj
->getProperty(cx
, id
, &pval
))
1728 if (JSVAL_IS_PRIMITIVE(pval
)) {
1730 * Throw a runtime error if instanceof is called on a function that
1731 * has a non-object as its .prototype value.
1733 js_ReportValueError(cx
, JSMSG_BAD_PROTOTYPE
,
1734 -1, OBJECT_TO_JSVAL(obj
), NULL
);
1738 return js_IsDelegate(cx
, JSVAL_TO_OBJECT(pval
), v
, bp
);
1742 TraceLocalNames(JSTracer
*trc
, JSFunction
*fun
);
1745 DestroyLocalNames(JSContext
*cx
, JSFunction
*fun
);
1748 fun_trace(JSTracer
*trc
, JSObject
*obj
)
1750 /* A newborn function object may have a not yet initialized private slot. */
1751 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
1755 if (FUN_OBJECT(fun
) != obj
) {
1756 /* obj is cloned function object, trace the original. */
1757 JS_CALL_TRACER(trc
, FUN_OBJECT(fun
), JSTRACE_OBJECT
, "private");
1761 JS_CALL_STRING_TRACER(trc
, ATOM_TO_STRING(fun
->atom
), "atom");
1762 if (FUN_INTERPRETED(fun
)) {
1763 if (fun
->u
.i
.script
)
1764 js_TraceScript(trc
, fun
->u
.i
.script
);
1765 TraceLocalNames(trc
, fun
);
1770 fun_finalize(JSContext
*cx
, JSObject
*obj
)
1772 /* Ignore newborn and cloned function objects. */
1773 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
1774 if (!fun
|| FUN_OBJECT(fun
) != obj
)
1778 * Null-check of u.i.script is required since the parser sets interpreted
1781 if (FUN_INTERPRETED(fun
)) {
1782 if (fun
->u
.i
.script
)
1783 js_DestroyScript(cx
, fun
->u
.i
.script
);
1784 DestroyLocalNames(cx
, fun
);
1789 JSFunction::sharpSlotBase(JSContext
*cx
)
1791 #if JS_HAS_SHARP_VARS
1792 JSAtom
*name
= js_Atomize(cx
, "#array", 6, 0);
1794 uintN index
= uintN(-1);
1798 js_LookupLocal(cx
, this, name
, &index
);
1799 JS_ASSERT(kind
== JSLOCAL_VAR
);
1807 JSFunction::countInterpretedReservedSlots() const
1809 JS_ASSERT(FUN_INTERPRETED(this));
1811 return (u
.i
.nupvars
== 0) ? 0 : u
.i
.script
->upvars()->length
;
1815 fun_reserveSlots(JSContext
*cx
, JSObject
*obj
)
1818 * We use getPrivate and not GET_FUNCTION_PRIVATE because during
1819 * js_InitFunctionClass invocation the function is called before the
1820 * private slot of the function object is set.
1822 JSFunction
*fun
= (JSFunction
*) obj
->getPrivate();
1823 return (fun
&& FUN_INTERPRETED(fun
))
1824 ? fun
->countInterpretedReservedSlots()
1829 * Reserve two slots in all function objects for XPConnect. Note that this
1830 * does not bloat every instance, only those on which reserved slots are set,
1831 * and those on which ad-hoc properties are defined.
1833 JS_FRIEND_DATA(JSClass
) js_FunctionClass
= {
1835 JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
| JSCLASS_HAS_RESERVED_SLOTS(2) |
1836 JSCLASS_MARK_IS_TRACE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Function
),
1837 JS_PropertyStub
, JS_PropertyStub
,
1838 JS_PropertyStub
, JS_PropertyStub
,
1839 JS_EnumerateStub
, (JSResolveOp
)fun_resolve
,
1840 JS_ConvertStub
, fun_finalize
,
1843 js_XDRFunctionObject
, fun_hasInstance
,
1844 JS_CLASS_TRACE(fun_trace
), fun_reserveSlots
1848 fun_toStringHelper(JSContext
*cx
, uint32_t indent
, uintN argc
, jsval
*vp
)
1855 fval
= JS_THIS(cx
, vp
);
1856 if (JSVAL_IS_NULL(fval
))
1859 if (!VALUE_IS_FUNCTION(cx
, fval
)) {
1860 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1861 JSMSG_INCOMPATIBLE_PROTO
,
1862 js_Function_str
, js_toString_str
,
1863 JS_GetTypeName(cx
, JS_TypeOfValue(cx
, fval
)));
1867 obj
= JSVAL_TO_OBJECT(fval
);
1869 if (!ValueToECMAUint32(cx
, vp
[2], &indent
))
1873 JS_ASSERT(JS_ObjectIsFunction(cx
, obj
));
1874 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
1877 str
= JS_DecompileFunction(cx
, fun
, (uintN
)indent
);
1880 *vp
= STRING_TO_JSVAL(str
);
1885 fun_toString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1887 return fun_toStringHelper(cx
, 0, argc
, vp
);
1892 fun_toSource(JSContext
*cx
, uintN argc
, jsval
*vp
)
1894 return fun_toStringHelper(cx
, JS_DONT_PRETTY_PRINT
, argc
, vp
);
1899 js_fun_call(JSContext
*cx
, uintN argc
, jsval
*vp
)
1902 jsval fval
, *argv
, *invokevp
;
1909 obj
= JS_THIS_OBJECT(cx
, vp
);
1914 if (!js_IsCallable(fval
)) {
1915 str
= JS_ValueToString(cx
, fval
);
1917 const char *bytes
= js_GetStringBytes(cx
, str
);
1920 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1921 JSMSG_INCOMPATIBLE_PROTO
,
1922 js_Function_str
, js_call_str
,
1931 /* Call fun with its global object as the 'this' param if no args. */
1934 /* Otherwise convert the first arg to 'this' and skip over it. */
1935 if (!JSVAL_IS_PRIMITIVE(argv
[0]))
1936 obj
= JSVAL_TO_OBJECT(argv
[0]);
1937 else if (!js_ValueToObject(cx
, argv
[0], &obj
))
1943 /* Allocate stack space for fval, obj, and the args. */
1944 invokevp
= js_AllocStack(cx
, 2 + argc
, &mark
);
1948 /* Push fval, obj, and the args. */
1950 invokevp
[1] = OBJECT_TO_JSVAL(obj
);
1951 memcpy(invokevp
+ 2, argv
, argc
* sizeof *argv
);
1953 ok
= js_Invoke(cx
, argc
, invokevp
, 0);
1955 js_FreeStack(cx
, mark
);
1960 js_fun_apply(JSContext
*cx
, uintN argc
, jsval
*vp
)
1962 JSObject
*obj
, *aobj
;
1963 jsval fval
, *invokevp
, *sp
;
1966 JSBool arraylike
, ok
;
1971 /* Will get globalObject as 'this' and no other arguments. */
1972 return js_fun_call(cx
, argc
, vp
);
1977 obj
= JS_THIS_OBJECT(cx
, vp
);
1982 if (!js_IsCallable(fval
)) {
1983 str
= JS_ValueToString(cx
, fval
);
1985 const char *bytes
= js_GetStringBytes(cx
, str
);
1988 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1989 JSMSG_INCOMPATIBLE_PROTO
,
1990 js_Function_str
, js_apply_str
,
1997 /* Quell GCC overwarnings. */
2002 /* If the 2nd arg is null or void, call the function with 0 args. */
2003 if (JSVAL_IS_NULL(vp
[3]) || JSVAL_IS_VOID(vp
[3])) {
2006 /* The second arg must be an array (or arguments object). */
2007 arraylike
= JS_FALSE
;
2008 if (!JSVAL_IS_PRIMITIVE(vp
[3])) {
2009 aobj
= JSVAL_TO_OBJECT(vp
[3]);
2010 if (!js_IsArrayLike(cx
, aobj
, &arraylike
, &length
))
2014 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2015 JSMSG_BAD_APPLY_ARGS
, js_apply_str
);
2021 /* Convert the first arg to 'this' and skip over it. */
2022 if (!JSVAL_IS_PRIMITIVE(vp
[2]))
2023 obj
= JSVAL_TO_OBJECT(vp
[2]);
2024 else if (!js_ValueToObject(cx
, vp
[2], &obj
))
2027 /* Allocate stack space for fval, obj, and the args. */
2028 argc
= (uintN
)JS_MIN(length
, JS_ARGS_LENGTH_MAX
);
2029 invokevp
= js_AllocStack(cx
, 2 + argc
, &mark
);
2033 /* Push fval, obj, and aobj's elements as args. */
2036 *sp
++ = OBJECT_TO_JSVAL(obj
);
2037 if (aobj
&& aobj
->isArguments() && !aobj
->isArgsLengthOverridden()) {
2039 * Two cases, two loops: note how in the case of an active stack frame
2040 * backing aobj, even though we copy from fp->argv, we still must check
2041 * aobj->getArgsElement(i) for a hole, to handle a delete on the
2042 * corresponding arguments element. See args_delProperty.
2044 JSStackFrame
*fp
= (JSStackFrame
*) aobj
->getPrivate();
2046 memcpy(sp
, fp
->argv
, argc
* sizeof(jsval
));
2047 for (i
= 0; i
< argc
; i
++) {
2048 if (aobj
->getArgsElement(i
) == JSVAL_HOLE
) // suppress deleted element
2052 for (i
= 0; i
< argc
; i
++) {
2053 sp
[i
] = aobj
->getArgsElement(i
);
2054 if (sp
[i
] == JSVAL_HOLE
)
2059 for (i
= 0; i
< argc
; i
++) {
2060 ok
= aobj
->getProperty(cx
, INT_TO_JSID(jsint(i
)), sp
);
2067 ok
= js_Invoke(cx
, argc
, invokevp
, 0);
2070 js_FreeStack(cx
, mark
);
2075 static JS_REQUIRES_STACK JSBool
2076 fun_applyConstructor(JSContext
*cx
, uintN argc
, jsval
*vp
)
2081 jsval
*invokevp
, *sp
;
2084 if (JSVAL_IS_PRIMITIVE(vp
[2]) ||
2085 (aobj
= JSVAL_TO_OBJECT(vp
[2]),
2087 !aobj
->isArguments())) {
2088 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2089 JSMSG_BAD_APPLY_ARGS
, "__applyConstruct__");
2093 if (!js_GetLengthProperty(cx
, aobj
, &length
))
2096 if (length
> JS_ARGS_LENGTH_MAX
)
2097 length
= JS_ARGS_LENGTH_MAX
;
2098 invokevp
= js_AllocStack(cx
, 2 + length
, &mark
);
2104 *sp
++ = JSVAL_NULL
; /* this is filled automagically */
2105 for (i
= 0; i
< length
; i
++) {
2106 ok
= aobj
->getProperty(cx
, INT_TO_JSID(jsint(i
)), sp
);
2112 ok
= js_InvokeConstructor(cx
, length
, JS_TRUE
, invokevp
);
2115 js_FreeStack(cx
, mark
);
2120 static JSFunctionSpec function_methods
[] = {
2122 JS_FN(js_toSource_str
, fun_toSource
, 0,0),
2124 JS_FN(js_toString_str
, fun_toString
, 0,0),
2125 JS_FN(js_apply_str
, js_fun_apply
, 2,0),
2126 JS_FN(js_call_str
, js_fun_call
, 1,0),
2128 JS_FN("__applyConstructor__", fun_applyConstructor
, 1,0),
2134 Function(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2138 JSStackFrame
*fp
, *caller
;
2141 const char *filename
;
2143 JSString
*str
, *arg
;
2145 JSPrincipals
*principals
;
2146 jschar
*collected_args
, *cp
;
2148 size_t arg_length
, args_length
, old_args_length
;
2151 if (!JS_IsConstructing(cx
)) {
2152 obj
= NewObject(cx
, &js_FunctionClass
, NULL
, NULL
);
2155 *rval
= OBJECT_TO_JSVAL(obj
);
2158 * The constructor is called before the private slot is initialized so
2159 * we must use getPrivate, not GET_FUNCTION_PRIVATE here.
2161 if (obj
->getPrivate())
2166 * NB: (new Function) is not lexically closed by its caller, it's just an
2167 * anonymous function in the top-level scope that its constructor inhabits.
2168 * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
2169 * and so would a call to f from another top-level's script or function.
2171 * In older versions, before call objects, a new Function was adopted by
2172 * its running context's globalObject, which might be different from the
2173 * top-level reachable from scopeChain (in HTML frames, e.g.).
2175 parent
= JSVAL_TO_OBJECT(argv
[-2])->getParent();
2177 fun
= js_NewFunction(cx
, obj
, NULL
, 0, JSFUN_LAMBDA
| JSFUN_INTERPRETED
,
2178 parent
, cx
->runtime
->atomState
.anonymousAtom
);
2184 * Function is static and not called directly by other functions in this
2185 * file, therefore it is callable only as a native function by js_Invoke.
2186 * Find the scripted caller, possibly skipping other native frames such as
2187 * are built for Function.prototype.call or .apply activations that invoke
2188 * Function indirectly from a script.
2190 fp
= js_GetTopStackFrame(cx
);
2191 JS_ASSERT(!fp
->script
&& fp
->fun
&& fp
->fun
->u
.n
.native
== Function
);
2192 caller
= js_GetScriptedCaller(cx
, fp
);
2194 principals
= JS_EvalFramePrincipals(cx
, fp
, caller
);
2195 filename
= js_ComputeFilename(cx
, caller
, principals
, &lineno
);
2202 /* Belt-and-braces: check that the caller has access to parent. */
2203 if (!js_CheckPrincipalsAccess(cx
, parent
, principals
,
2204 CLASS_ATOM(cx
, Function
))) {
2209 * CSP check: whether new Function() is allowed at all.
2210 * Report errors via CSP is done in the script security manager.
2211 * js_CheckContentSecurityPolicy is defined in jsobj.cpp
2213 if (!js_CheckContentSecurityPolicy(cx
)) {
2214 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2215 JSMSG_CSP_BLOCKED_FUNCTION
);
2219 n
= argc
? argc
- 1 : 0;
2221 enum { OK
, BAD
, BAD_FORMAL
} state
;
2224 * Collect the function-argument arguments into one string, separated
2225 * by commas, then make a tokenstream from that string, and scan it to
2226 * get the arguments. We need to throw the full scanner at the
2227 * problem, because the argument string can legitimately contain
2228 * comments and linefeeds. XXX It might be better to concatenate
2229 * everything up into a function definition and pass it to the
2230 * compiler, but doing it this way is less of a delta from the old
2231 * code. See ECMA 15.3.2.1.
2235 for (i
= 0; i
< n
; i
++) {
2236 /* Collect the lengths for all the function-argument arguments. */
2237 arg
= js_ValueToString(cx
, argv
[i
]);
2240 argv
[i
] = STRING_TO_JSVAL(arg
);
2243 * Check for overflow. The < test works because the maximum
2244 * JSString length fits in 2 fewer bits than size_t has.
2246 old_args_length
= args_length
;
2247 args_length
= old_args_length
+ arg
->length();
2248 if (args_length
< old_args_length
) {
2249 js_ReportAllocationOverflow(cx
);
2254 /* Add 1 for each joining comma and check for overflow (two ways). */
2255 old_args_length
= args_length
;
2256 args_length
= old_args_length
+ n
- 1;
2257 if (args_length
< old_args_length
||
2258 args_length
>= ~(size_t)0 / sizeof(jschar
)) {
2259 js_ReportAllocationOverflow(cx
);
2264 * Allocate a string to hold the concatenated arguments, including room
2265 * for a terminating 0. Mark cx->tempPool for later release, to free
2266 * collected_args and its tokenstream in one swoop.
2268 mark
= JS_ARENA_MARK(&cx
->tempPool
);
2269 JS_ARENA_ALLOCATE_CAST(cp
, jschar
*, &cx
->tempPool
,
2270 (args_length
+1) * sizeof(jschar
));
2272 js_ReportOutOfScriptQuota(cx
);
2275 collected_args
= cp
;
2278 * Concatenate the arguments into the new string, separated by commas.
2280 for (i
= 0; i
< n
; i
++) {
2281 arg
= JSVAL_TO_STRING(argv
[i
]);
2282 arg_length
= arg
->length();
2283 (void) js_strncpy(cp
, arg
->chars(), arg_length
);
2286 /* Add separating comma or terminating 0. */
2287 *cp
++ = (i
+ 1 < n
) ? ',' : 0;
2290 /* Initialize a tokenstream that reads from the given string. */
2291 if (!ts
.init(collected_args
, args_length
, NULL
, filename
, lineno
)) {
2292 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2296 /* The argument string may be empty or contain no tokens. */
2298 if (tt
!= TOK_EOF
) {
2301 * Check that it's a name. This also implicitly guards against
2302 * TOK_ERROR, which was already reported.
2308 * Get the atom corresponding to the name from the token
2309 * stream; we're assured at this point that it's a valid
2312 atom
= ts
.currentToken().t_atom
;
2314 /* Check for a duplicate parameter name. */
2315 if (js_LookupLocal(cx
, fun
, atom
, NULL
) != JSLOCAL_NONE
) {
2318 name
= js_AtomToPrintableString(cx
, atom
);
2319 ok
= name
&& ReportCompileErrorNumber(cx
, &ts
, NULL
,
2320 JSREPORT_WARNING
| JSREPORT_STRICT
,
2321 JSMSG_DUPLICATE_FORMAL
, name
);
2325 if (!js_AddLocal(cx
, fun
, atom
, JSLOCAL_ARG
))
2329 * Get the next token. Stop on end of stream. Otherwise
2330 * insist on a comma, get another name, and iterate.
2335 if (tt
!= TOK_COMMA
)
2343 if (state
== BAD_FORMAL
&& !ts
.isError()) {
2345 * Report "malformed formal parameter" iff no illegal char or
2346 * similar scanner error was already reported.
2348 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2352 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2358 str
= js_ValueToString(cx
, argv
[argc
-1]);
2361 argv
[argc
-1] = STRING_TO_JSVAL(str
);
2363 str
= cx
->runtime
->emptyString
;
2366 return Compiler::compileFunctionBody(cx
, fun
, principals
,
2367 str
->chars(), str
->length(),
2372 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
)
2377 proto
= JS_InitClass(cx
, obj
, NULL
, &js_FunctionClass
, Function
, 1,
2378 function_props
, function_methods
, NULL
, NULL
);
2381 fun
= js_NewFunction(cx
, proto
, NULL
, 0, JSFUN_INTERPRETED
, obj
, NULL
);
2384 fun
->u
.i
.script
= JSScript::emptyScript();
2389 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, JSNative native
, uintN nargs
,
2390 uintN flags
, JSObject
*parent
, JSAtom
*atom
)
2395 JS_ASSERT(funobj
->isFunction());
2396 funobj
->setParent(parent
);
2398 funobj
= NewObject(cx
, &js_FunctionClass
, NULL
, parent
);
2402 JS_ASSERT(!funobj
->getPrivate());
2403 fun
= (JSFunction
*) funobj
;
2405 /* Initialize all function members. */
2406 fun
->nargs
= uint16(nargs
);
2407 fun
->flags
= flags
& (JSFUN_FLAGS_MASK
| JSFUN_KINDMASK
| JSFUN_TRCINFO
);
2408 if ((flags
& JSFUN_KINDMASK
) >= JSFUN_INTERPRETED
) {
2410 JS_ASSERT(nargs
== 0);
2412 fun
->u
.i
.nupvars
= 0;
2413 fun
->u
.i
.skipmin
= 0;
2414 fun
->u
.i
.wrapper
= false;
2415 fun
->u
.i
.script
= NULL
;
2417 fun
->u
.i
.names
.taggedAtom
= 0;
2422 fun
->u
.n
.clasp
= NULL
;
2423 if (flags
& JSFUN_TRCINFO
) {
2425 JSNativeTraceInfo
*trcinfo
=
2426 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo
*, native
);
2427 fun
->u
.n
.native
= (JSNative
) trcinfo
->native
;
2428 fun
->u
.n
.trcinfo
= trcinfo
;
2430 fun
->u
.n
.trcinfo
= NULL
;
2433 fun
->u
.n
.native
= native
;
2434 fun
->u
.n
.trcinfo
= NULL
;
2436 JS_ASSERT(fun
->u
.n
.native
);
2440 /* Set private to self to indicate non-cloned fully initialized function. */
2441 FUN_OBJECT(fun
)->setPrivate(fun
);
2445 JSObject
* JS_FASTCALL
2446 js_CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
,
2453 * The cloned function object does not need the extra JSFunction members
2454 * beyond JSObject as it points to fun via the private slot.
2456 JSObject
*clone
= NewObjectWithGivenProto(cx
, &js_FunctionClass
, proto
,
2457 parent
, sizeof(JSObject
));
2460 clone
->setPrivate(fun
);
2465 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_CloneFunctionObject
, CONTEXT
, FUNCTION
, OBJECT
, OBJECT
, 0,
2466 nanojit::ACC_STORE_ANY
)
2470 * Create a new flat closure, but don't initialize the imported upvar
2471 * values. The tracer calls this function and then initializes the upvar
2474 JSObject
* JS_FASTCALL
2475 js_AllocFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
)
2477 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
2478 JS_ASSERT((fun
->u
.i
.script
->upvarsOffset
2479 ? fun
->u
.i
.script
->upvars()->length
2480 : 0) == fun
->u
.i
.nupvars
);
2482 JSObject
*closure
= CloneFunctionObject(cx
, fun
, scopeChain
);
2486 uint32 nslots
= fun
->countInterpretedReservedSlots();
2489 if (!js_EnsureReservedSlots(cx
, closure
, nslots
))
2495 JS_DEFINE_CALLINFO_3(extern, OBJECT
, js_AllocFlatClosure
,
2496 CONTEXT
, FUNCTION
, OBJECT
, 0, nanojit::ACC_STORE_ANY
)
2498 JS_REQUIRES_STACK JSObject
*
2499 js_NewFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2502 * Flat closures can be partial, they may need to search enclosing scope
2503 * objects via JSOP_NAME, etc.
2505 JSObject
*scopeChain
= js_GetScopeChain(cx
, cx
->fp
);
2509 JSObject
*closure
= js_AllocFlatClosure(cx
, fun
, scopeChain
);
2510 if (!closure
|| fun
->u
.i
.nupvars
== 0)
2513 JSUpvarArray
*uva
= fun
->u
.i
.script
->upvars();
2514 JS_ASSERT(uva
->length
<= size_t(closure
->dslots
[-1]));
2516 uintN level
= fun
->u
.i
.script
->staticLevel
;
2517 for (uint32 i
= 0, n
= uva
->length
; i
< n
; i
++)
2518 closure
->dslots
[i
] = js_GetUpvar(cx
, level
, uva
->vector
[i
]);
2524 js_NewDebuggableFlatClosure(JSContext
*cx
, JSFunction
*fun
)
2526 JS_ASSERT(cx
->fp
->fun
->flags
& JSFUN_HEAVYWEIGHT
);
2527 JS_ASSERT(!cx
->fp
->fun
->optimizedClosure());
2528 JS_ASSERT(FUN_FLAT_CLOSURE(fun
));
2530 return WrapEscapingClosure(cx
, cx
->fp
, FUN_OBJECT(fun
), fun
);
2534 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
, JSNative native
,
2535 uintN nargs
, uintN attrs
)
2540 if (attrs
& JSFUN_STUB_GSOPS
) {
2542 * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2543 * the defined property's attributes. This allows us to encode another,
2544 * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2547 attrs
&= ~JSFUN_STUB_GSOPS
;
2548 gsop
= JS_PropertyStub
;
2552 fun
= js_NewFunction(cx
, NULL
, native
, nargs
, attrs
, obj
, atom
);
2555 if (!obj
->defineProperty(cx
, ATOM_TO_JSID(atom
), OBJECT_TO_JSVAL(FUN_OBJECT(fun
)),
2556 gsop
, gsop
, attrs
& ~JSFUN_FLAGS_MASK
)) {
2562 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2563 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2567 js_ValueToFunction(JSContext
*cx
, jsval
*vp
, uintN flags
)
2572 if (!VALUE_IS_FUNCTION(cx
, v
)) {
2573 js_ReportIsNotFunction(cx
, vp
, flags
);
2576 return GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(v
));
2580 js_ValueToFunctionObject(JSContext
*cx
, jsval
*vp
, uintN flags
)
2583 JSStackFrame
*caller
;
2584 JSPrincipals
*principals
;
2586 if (VALUE_IS_FUNCTION(cx
, *vp
))
2587 return JSVAL_TO_OBJECT(*vp
);
2589 fun
= js_ValueToFunction(cx
, vp
, flags
);
2592 *vp
= OBJECT_TO_JSVAL(FUN_OBJECT(fun
));
2594 caller
= js_GetScriptedCaller(cx
, NULL
);
2596 principals
= JS_StackFramePrincipals(cx
, caller
);
2598 /* No scripted caller, don't allow access. */
2602 if (!js_CheckPrincipalsAccess(cx
, FUN_OBJECT(fun
), principals
,
2605 : cx
->runtime
->atomState
.anonymousAtom
)) {
2608 return FUN_OBJECT(fun
);
2612 js_ValueToCallableObject(JSContext
*cx
, jsval
*vp
, uintN flags
)
2614 JSObject
*callable
= JSVAL_IS_OBJECT(*vp
) ? JSVAL_TO_OBJECT(*vp
) : NULL
;
2616 if (callable
&& callable
->isCallable()) {
2617 *vp
= OBJECT_TO_JSVAL(callable
);
2620 return js_ValueToFunctionObject(cx
, vp
, flags
);
2624 js_ReportIsNotFunction(JSContext
*cx
, jsval
*vp
, uintN flags
)
2628 const char *name
, *source
;
2630 for (fp
= js_GetTopStackFrame(cx
); fp
&& !fp
->regs
; fp
= fp
->down
)
2632 name
= source
= NULL
;
2634 AutoValueRooter
tvr(cx
);
2635 if (flags
& JSV2F_ITERATOR
) {
2636 error
= JSMSG_BAD_ITERATOR
;
2637 name
= js_iterator_str
;
2638 JSString
*src
= js_ValueToSource(cx
, *vp
);
2642 JSString
*qsrc
= js_QuoteString(cx
, src
, 0);
2645 tvr
.setString(qsrc
);
2646 source
= js_GetStringBytes(cx
, qsrc
);
2649 } else if (flags
& JSV2F_CONSTRUCT
) {
2650 error
= JSMSG_NOT_CONSTRUCTOR
;
2652 error
= JSMSG_NOT_FUNCTION
;
2655 js_ReportValueError3(cx
, error
,
2657 StackBase(fp
) <= vp
&& vp
< fp
->regs
->sp
)
2659 : (flags
& JSV2F_SEARCH_STACK
)
2660 ? JSDVG_SEARCH_STACK
2661 : JSDVG_IGNORE_STACK
,
2667 * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
2668 * their name are stored as the JSLocalNames.array.
2670 #define MAX_ARRAY_LOCALS 8
2672 JS_STATIC_ASSERT(2 <= MAX_ARRAY_LOCALS
);
2673 JS_STATIC_ASSERT(MAX_ARRAY_LOCALS
< JS_BITMASK(16));
2676 * We use the lowest bit of the string atom to distinguish const from var
2677 * name when there is only single name or when names are stored as an array.
2679 JS_STATIC_ASSERT((JSVAL_STRING
& 1) == 0);
2682 * When we use a hash table to store the local names, we use a singly linked
2683 * list to record the indexes of duplicated parameter names to preserve the
2684 * duplicates for the decompiler.
2686 typedef struct JSNameIndexPair JSNameIndexPair
;
2688 struct JSNameIndexPair
{
2691 JSNameIndexPair
*link
;
2694 struct JSLocalNameMap
{
2696 JSNameIndexPair
*lastdup
;
2699 typedef struct JSLocalNameHashEntry
{
2700 JSDHashEntryHdr hdr
;
2704 } JSLocalNameHashEntry
;
2707 FreeLocalNameHash(JSContext
*cx
, JSLocalNameMap
*map
)
2709 JSNameIndexPair
*dup
, *next
;
2711 for (dup
= map
->lastdup
; dup
; dup
= next
) {
2715 JS_DHashTableFinish(&map
->names
);
2720 HashLocalName(JSContext
*cx
, JSLocalNameMap
*map
, JSAtom
*name
,
2721 JSLocalKind localKind
, uintN index
)
2723 JSLocalNameHashEntry
*entry
;
2724 JSNameIndexPair
*dup
;
2726 JS_ASSERT(index
<= JS_BITMASK(16));
2727 #if JS_HAS_DESTRUCTURING
2729 /* A destructuring pattern does not need a hash entry. */
2730 JS_ASSERT(localKind
== JSLOCAL_ARG
);
2734 JS_ASSERT(ATOM_IS_STRING(name
));
2735 entry
= (JSLocalNameHashEntry
*)
2736 JS_DHashTableOperate(&map
->names
, name
, JS_DHASH_ADD
);
2738 JS_ReportOutOfMemory(cx
);
2742 JS_ASSERT(entry
->name
== name
);
2743 JS_ASSERT(entry
->localKind
== JSLOCAL_ARG
&& localKind
== JSLOCAL_ARG
);
2744 dup
= (JSNameIndexPair
*) cx
->malloc(sizeof *dup
);
2747 dup
->name
= entry
->name
;
2748 dup
->index
= entry
->index
;
2749 dup
->link
= map
->lastdup
;
2753 entry
->index
= (uint16
) index
;
2754 entry
->localKind
= (uint8
) localKind
;
2759 js_AddLocal(JSContext
*cx
, JSFunction
*fun
, JSAtom
*atom
, JSLocalKind kind
)
2765 JSLocalNameMap
*map
;
2767 JS_ASSERT(FUN_INTERPRETED(fun
));
2768 JS_ASSERT(!fun
->u
.i
.script
);
2769 JS_ASSERT(((jsuword
) atom
& 1) == 0);
2770 taggedAtom
= (jsuword
) atom
;
2771 if (kind
== JSLOCAL_ARG
) {
2772 indexp
= &fun
->nargs
;
2773 } else if (kind
== JSLOCAL_UPVAR
) {
2774 indexp
= &fun
->u
.i
.nupvars
;
2776 indexp
= &fun
->u
.i
.nvars
;
2777 if (kind
== JSLOCAL_CONST
)
2780 JS_ASSERT(kind
== JSLOCAL_VAR
);
2782 n
= fun
->countLocalNames();
2784 JS_ASSERT(fun
->u
.i
.names
.taggedAtom
== 0);
2785 fun
->u
.i
.names
.taggedAtom
= taggedAtom
;
2786 } else if (n
< MAX_ARRAY_LOCALS
) {
2788 array
= fun
->u
.i
.names
.array
;
2790 array
= (jsuword
*) cx
->malloc(MAX_ARRAY_LOCALS
* sizeof *array
);
2793 array
[0] = fun
->u
.i
.names
.taggedAtom
;
2794 fun
->u
.i
.names
.array
= array
;
2796 if (kind
== JSLOCAL_ARG
) {
2798 * A destructuring argument pattern adds variables, not arguments,
2799 * so for the following arguments nvars != 0.
2801 #if JS_HAS_DESTRUCTURING
2802 if (fun
->u
.i
.nvars
!= 0) {
2803 memmove(array
+ fun
->nargs
+ 1, array
+ fun
->nargs
,
2804 fun
->u
.i
.nvars
* sizeof *array
);
2807 JS_ASSERT(fun
->u
.i
.nvars
== 0);
2809 array
[fun
->nargs
] = taggedAtom
;
2811 array
[n
] = taggedAtom
;
2813 } else if (n
== MAX_ARRAY_LOCALS
) {
2814 array
= fun
->u
.i
.names
.array
;
2815 map
= (JSLocalNameMap
*) cx
->malloc(sizeof *map
);
2818 if (!JS_DHashTableInit(&map
->names
, JS_DHashGetStubOps(),
2819 NULL
, sizeof(JSLocalNameHashEntry
),
2820 JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS
2822 JS_ReportOutOfMemory(cx
);
2827 map
->lastdup
= NULL
;
2828 for (i
= 0; i
!= MAX_ARRAY_LOCALS
; ++i
) {
2829 taggedAtom
= array
[i
];
2831 JSLocalKind k
= JSLOCAL_ARG
;
2832 if (j
>= fun
->nargs
) {
2834 if (j
< fun
->u
.i
.nvars
) {
2835 k
= (taggedAtom
& 1) ? JSLOCAL_CONST
: JSLOCAL_VAR
;
2837 j
-= fun
->u
.i
.nvars
;
2841 if (!HashLocalName(cx
, map
, (JSAtom
*) (taggedAtom
& ~1), k
, j
)) {
2842 FreeLocalNameHash(cx
, map
);
2846 if (!HashLocalName(cx
, map
, atom
, kind
, *indexp
)) {
2847 FreeLocalNameHash(cx
, map
);
2852 * At this point the entry is added and we cannot fail. It is time
2853 * to replace fun->u.i.names with the built map.
2855 fun
->u
.i
.names
.map
= map
;
2858 if (*indexp
== JS_BITMASK(16)) {
2859 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2860 (kind
== JSLOCAL_ARG
)
2861 ? JSMSG_TOO_MANY_FUN_ARGS
2862 : JSMSG_TOO_MANY_LOCALS
);
2865 if (!HashLocalName(cx
, fun
->u
.i
.names
.map
, atom
, kind
, *indexp
))
2869 /* Update the argument or variable counter. */
2875 js_LookupLocal(JSContext
*cx
, JSFunction
*fun
, JSAtom
*atom
, uintN
*indexp
)
2877 uintN n
, i
, upvar_base
;
2879 JSLocalNameHashEntry
*entry
;
2881 JS_ASSERT(FUN_INTERPRETED(fun
));
2882 n
= fun
->countLocalNames();
2884 return JSLOCAL_NONE
;
2885 if (n
<= MAX_ARRAY_LOCALS
) {
2886 array
= (n
== 1) ? &fun
->u
.i
.names
.taggedAtom
: fun
->u
.i
.names
.array
;
2888 /* Search from the tail to pick up the last duplicated name. */
2890 upvar_base
= fun
->countArgsAndVars();
2893 if (atom
== JS_LOCAL_NAME_TO_ATOM(array
[i
])) {
2894 if (i
< fun
->nargs
) {
2899 if (i
>= upvar_base
) {
2901 *indexp
= i
- upvar_base
;
2902 return JSLOCAL_UPVAR
;
2905 *indexp
= i
- fun
->nargs
;
2906 return JS_LOCAL_NAME_IS_CONST(array
[i
])
2912 entry
= (JSLocalNameHashEntry
*)
2913 JS_DHashTableOperate(&fun
->u
.i
.names
.map
->names
, atom
,
2915 if (JS_DHASH_ENTRY_IS_BUSY(&entry
->hdr
)) {
2916 JS_ASSERT(entry
->localKind
!= JSLOCAL_NONE
);
2918 *indexp
= entry
->index
;
2919 return (JSLocalKind
) entry
->localKind
;
2922 return JSLOCAL_NONE
;
2925 typedef struct JSLocalNameEnumeratorArgs
{
2932 } JSLocalNameEnumeratorArgs
;
2934 static JSDHashOperator
2935 get_local_names_enumerator(JSDHashTable
*table
, JSDHashEntryHdr
*hdr
,
2936 uint32 number
, void *arg
)
2938 JSLocalNameHashEntry
*entry
;
2939 JSLocalNameEnumeratorArgs
*args
;
2943 entry
= (JSLocalNameHashEntry
*) hdr
;
2944 args
= (JSLocalNameEnumeratorArgs
*) arg
;
2945 JS_ASSERT(entry
->name
);
2946 if (entry
->localKind
== JSLOCAL_ARG
) {
2947 JS_ASSERT(entry
->index
< args
->fun
->nargs
);
2948 JS_ASSERT(args
->nCopiedArgs
++ < args
->fun
->nargs
);
2952 JS_ASSERT(entry
->localKind
== JSLOCAL_VAR
||
2953 entry
->localKind
== JSLOCAL_CONST
||
2954 entry
->localKind
== JSLOCAL_UPVAR
);
2955 JS_ASSERT(entry
->index
< args
->fun
->u
.i
.nvars
+ args
->fun
->u
.i
.nupvars
);
2956 JS_ASSERT(args
->nCopiedVars
++ < unsigned(args
->fun
->u
.i
.nvars
+ args
->fun
->u
.i
.nupvars
));
2957 i
= args
->fun
->nargs
;
2958 if (entry
->localKind
== JSLOCAL_UPVAR
)
2959 i
+= args
->fun
->u
.i
.nvars
;
2961 constFlag
= (entry
->localKind
== JSLOCAL_CONST
);
2963 args
->names
[i
] = (jsuword
) entry
->name
| constFlag
;
2964 return JS_DHASH_NEXT
;
2967 JS_FRIEND_API(jsuword
*)
2968 js_GetLocalNameArray(JSContext
*cx
, JSFunction
*fun
, JSArenaPool
*pool
)
2972 JSLocalNameMap
*map
;
2973 JSLocalNameEnumeratorArgs args
;
2974 JSNameIndexPair
*dup
;
2976 JS_ASSERT(fun
->hasLocalNames());
2977 n
= fun
->countLocalNames();
2979 if (n
<= MAX_ARRAY_LOCALS
)
2980 return (n
== 1) ? &fun
->u
.i
.names
.taggedAtom
: fun
->u
.i
.names
.array
;
2983 * No need to check for overflow of the allocation size as we are making a
2984 * copy of already allocated data. As such it must fit size_t.
2986 JS_ARENA_ALLOCATE_CAST(names
, jsuword
*, pool
, (size_t) n
* sizeof *names
);
2988 js_ReportOutOfScriptQuota(cx
);
2992 #if JS_HAS_DESTRUCTURING
2993 /* Some parameter names can be NULL due to destructuring patterns. */
2994 PodZero(names
, fun
->nargs
);
2996 map
= fun
->u
.i
.names
.map
;
3000 args
.nCopiedArgs
= 0;
3001 args
.nCopiedVars
= 0;
3003 JS_DHashTableEnumerate(&map
->names
, get_local_names_enumerator
, &args
);
3004 for (dup
= map
->lastdup
; dup
; dup
= dup
->link
) {
3005 JS_ASSERT(dup
->index
< fun
->nargs
);
3006 JS_ASSERT(args
.nCopiedArgs
++ < fun
->nargs
);
3007 names
[dup
->index
] = (jsuword
) dup
->name
;
3009 #if !JS_HAS_DESTRUCTURING
3010 JS_ASSERT(args
.nCopiedArgs
== fun
->nargs
);
3012 JS_ASSERT(args
.nCopiedVars
== fun
->u
.i
.nvars
+ fun
->u
.i
.nupvars
);
3017 static JSDHashOperator
3018 trace_local_names_enumerator(JSDHashTable
*table
, JSDHashEntryHdr
*hdr
,
3019 uint32 number
, void *arg
)
3021 JSLocalNameHashEntry
*entry
;
3024 entry
= (JSLocalNameHashEntry
*) hdr
;
3025 JS_ASSERT(entry
->name
);
3026 trc
= (JSTracer
*) arg
;
3027 JS_SET_TRACING_INDEX(trc
,
3028 entry
->localKind
== JSLOCAL_ARG
? "arg" : "var",
3030 js_CallGCMarker(trc
, ATOM_TO_STRING(entry
->name
), JSTRACE_STRING
);
3031 return JS_DHASH_NEXT
;
3035 TraceLocalNames(JSTracer
*trc
, JSFunction
*fun
)
3041 JS_ASSERT(FUN_INTERPRETED(fun
));
3042 n
= fun
->countLocalNames();
3045 if (n
<= MAX_ARRAY_LOCALS
) {
3046 array
= (n
== 1) ? &fun
->u
.i
.names
.taggedAtom
: fun
->u
.i
.names
.array
;
3050 atom
= (JSAtom
*) (array
[i
] & ~1);
3052 JS_SET_TRACING_INDEX(trc
,
3053 i
< fun
->nargs
? "arg" : "var",
3054 i
< fun
->nargs
? i
: i
- fun
->nargs
);
3055 js_CallGCMarker(trc
, ATOM_TO_STRING(atom
), JSTRACE_STRING
);
3059 JS_DHashTableEnumerate(&fun
->u
.i
.names
.map
->names
,
3060 trace_local_names_enumerator
, trc
);
3063 * No need to trace the list of duplicates in map->lastdup as the
3064 * names there are traced when enumerating the hash table.
3070 DestroyLocalNames(JSContext
*cx
, JSFunction
*fun
)
3074 n
= fun
->countLocalNames();
3077 if (n
<= MAX_ARRAY_LOCALS
)
3078 cx
->free(fun
->u
.i
.names
.array
);
3080 FreeLocalNameHash(cx
, fun
->u
.i
.names
.map
);
3084 js_FreezeLocalNames(JSContext
*cx
, JSFunction
*fun
)
3089 JS_ASSERT(FUN_INTERPRETED(fun
));
3090 JS_ASSERT(!fun
->u
.i
.script
);
3091 n
= fun
->nargs
+ fun
->u
.i
.nvars
+ fun
->u
.i
.nupvars
;
3092 if (2 <= n
&& n
< MAX_ARRAY_LOCALS
) {
3093 /* Shrink over-allocated array ignoring realloc failures. */
3094 array
= (jsuword
*) cx
->realloc(fun
->u
.i
.names
.array
,
3097 fun
->u
.i
.names
.array
= array
;
3100 if (n
> MAX_ARRAY_LOCALS
)
3101 JS_DHashMarkTableImmutable(&fun
->u
.i
.names
.map
->names
);
3106 JSFunction::findDuplicateFormal() const
3111 /* Function with two to MAX_ARRAY_LOCALS parameters use an aray. */
3112 unsigned n
= nargs
+ u
.i
.nvars
+ u
.i
.nupvars
;
3113 if (n
<= MAX_ARRAY_LOCALS
) {
3114 jsuword
*array
= u
.i
.names
.array
;
3116 /* Quadratic, but MAX_ARRAY_LOCALS is 8, so at most 28 comparisons. */
3117 for (unsigned i
= 0; i
< nargs
; i
++) {
3118 for (unsigned j
= i
+ 1; j
< nargs
; j
++) {
3119 if (array
[i
] == array
[j
])
3120 return JS_LOCAL_NAME_TO_ATOM(array
[i
]);
3127 * Functions with more than MAX_ARRAY_LOCALS parameters use a hash
3128 * table. Hashed local name maps have already made a list of any
3129 * duplicate argument names for us.
3131 JSNameIndexPair
*dup
= u
.i
.names
.map
->lastdup
;
3132 return dup
? dup
->name
: NULL
;