1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
43 * JS function definitions.
54 * The high two bits of JSFunction.flags encode whether the function is native
55 * or interpreted, and if interpreted, what kind of optimized closure form (if
59 * 01 interpreted, neither flat nor null closure
60 * 10 interpreted, flat closure
61 * 11 interpreted, null closure
63 * FUN_FLAT_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset != 0.
64 * FUN_NULL_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset == 0.
66 * FUN_INTERPRETED but not FUN_FLAT_CLOSURE and u.i.script->upvarsOffset != 0
67 * is an Algol-like function expression or nested function, i.e., a function
68 * that never escapes upward or downward (heapward), and is only ever called.
70 * Finally, FUN_INTERPRETED and u.i.script->upvarsOffset == 0 could be either
71 * a non-closure (a global function definition, or any function that uses no
72 * outer names), or a closure of an escaping function that uses outer names
73 * whose values can't be snapshot (because the outer names could be reassigned
74 * after the closure is formed, or because assignments could not be analyzed
75 * due to with or eval).
77 * Such a hard-case function must use JSOP_NAME, etc., and reify outer function
78 * activations' call objects, etc. if it's not a global function.
80 * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
81 * bit only, never stored in fun->flags.
83 * If we need more bits in the future, all flags for FUN_INTERPRETED functions
84 * can move to u.i.script->flags. For now we use function flag bits to minimize
87 #define JSFUN_JOINABLE 0x0001 /* function is null closure that does not
88 appear to call itself via its own name
89 or arguments.callee */
91 #define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
94 #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
95 #define JSFUN_TRCINFO 0x2000 /* when set, u.n.trcinfo is non-null,
96 JSFunctionSpec::call points to a
98 #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
99 #define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */
100 #define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
101 #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
102 optimization level -- see above */
104 #define FUN_OBJECT(fun) (static_cast<JSObject *>(fun))
105 #define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK)
106 #define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k))
107 #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED)
108 #define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE)
109 #define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE)
110 #define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL)
111 #define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \
113 #define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \
114 JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \
117 struct JSFunction
: public JSObject_Slots2
119 /* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */
121 uint16 nargs
; /* maximum number of specified arguments,
122 reflected as f.length/f.arity */
123 uint16 flags
; /* flags, see JSFUN_* below and in jsapi.h */
126 js::Native native
; /* native method pointer or null */
127 js::Class
*clasp
; /* class of objects constructed
129 JSNativeTraceInfo
*trcinfo
;
132 JSScript
*script
; /* interpreted bytecode descriptor or null */
133 uint16 skipmin
; /* net skip amount up (toward zero) from
134 script->staticLevel to nearest upvar,
135 including upvars in nested functions */
136 JSPackedBool wrapper
; /* true if this function is a wrapper that
137 rewrites bytecode optimized for a function
138 judged non-escaping by the compiler, which
139 then escaped via the debugger or a rogue
140 indirect eval; if true, then this function
141 object's proto is the wrapped object */
142 js::Shape
*names
; /* argument and variable names */
144 void *nativeOrScript
;
146 JSAtom
*atom
; /* name for diagnostics and decompiling */
148 bool optimizedClosure() const { return FUN_KIND(this) > JSFUN_INTERPRETED
; }
149 bool needsWrapper() const { return FUN_NULL_CLOSURE(this) && u
.i
.skipmin
!= 0; }
150 bool isInterpreted() const { return FUN_INTERPRETED(this); }
151 bool isNative() const { return !FUN_INTERPRETED(this); }
152 bool isConstructor() const { return flags
& JSFUN_CONSTRUCTOR
; }
153 bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags
); }
154 bool isFlatClosure() const { return FUN_KIND(this) == JSFUN_FLAT_CLOSURE
; }
156 bool isFunctionPrototype() const { return flags
& JSFUN_PROTOTYPE
; }
158 /* Returns the strictness of this function, which must be interpreted. */
159 inline bool inStrictMode() const;
161 void setArgCount(uint16 nargs
) {
162 JS_ASSERT(this->nargs
== 0);
166 /* uint16 representation bounds number of call object dynamic slots. */
167 enum { MAX_ARGS_AND_VARS
= 2 * ((1U << 16) - 1) };
169 #define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~(jsuword) 1))
170 #define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & (jsuword) 1)) != 0)
172 bool mightEscape() const {
173 return isInterpreted() && (isFlatClosure() || !script()->bindings
.hasUpvars());
176 bool joinable() const {
177 return flags
& JSFUN_JOINABLE
;
180 JSObject
&compiledFunObj() {
186 * js_FunctionClass reserves two slots, which are free in JSObject::fslots
187 * without requiring dslots allocation. Null closures that can be joined to
188 * a compiler-created function object use the first one to hold a mutable
189 * methodAtom() state variable, needed for correct foo.caller handling.
192 METHOD_ATOM_SLOT
= JSSLOT_FUN_METHOD_ATOM
197 JS_ASSERT(FUN_INTERPRETED(this));
198 getSlotRef(METHOD_ATOM_SLOT
).setNull();
199 flags
|= JSFUN_JOINABLE
;
203 * Method name imputed from property uniquely assigned to or initialized,
204 * where the function does not need to be cloned to carry a scope chain or
207 JSAtom
*methodAtom() const {
208 return (joinable() && getSlot(METHOD_ATOM_SLOT
).isString())
209 ? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT
).toString())
213 void setMethodAtom(JSAtom
*atom
) {
214 JS_ASSERT(joinable());
215 getSlotRef(METHOD_ATOM_SLOT
).setString(ATOM_TO_STRING(atom
));
218 js::Native
maybeNative() const {
219 return isInterpreted() ? NULL
: u
.n
.native
;
222 JSScript
*script() const {
223 JS_ASSERT(isInterpreted());
227 static uintN
offsetOfNativeOrScript() {
228 JS_STATIC_ASSERT(offsetof(U
, n
.native
) == offsetof(U
, i
.script
));
229 JS_STATIC_ASSERT(offsetof(U
, n
.native
) == offsetof(U
, nativeOrScript
));
230 return offsetof(JSFunction
, u
.nativeOrScript
);
233 /* Number of extra fixed function object slots. */
234 static const uint32 CLASS_RESERVED_SLOTS
= JSObject::FUN_CLASS_RESERVED_SLOTS
;
238 * Trace-annotated native. This expands to a JSFunctionSpec initializer (like
239 * JS_FN in jsapi.h). fastcall is a FastNative; trcinfo is a
240 * JSNativeTraceInfo*.
243 /* MSVC demands the intermediate (void *) cast here. */
244 # define JS_TN(name,fastcall,nargs,flags,trcinfo) \
245 JS_FN(name, JS_DATA_TO_FUNC_PTR(Native, trcinfo), nargs, \
246 (flags) | JSFUN_STUB_GSOPS | JSFUN_TRCINFO)
248 # define JS_TN(name,fastcall,nargs,flags,trcinfo) \
249 JS_FN(name, fastcall, nargs, flags)
253 * NB: the Arguments classes are uninitialized internal classes that masquerade
254 * (according to Object.prototype.toString.call(arguments)) as "Arguments",
255 * while having Object.getPrototypeOf(arguments) === Object.prototype.
257 * WARNING (to alert embedders reading this private .h file): arguments objects
258 * are *not* thread-safe and should not be used concurrently -- they should be
259 * used by only one thread at a time, preferably by only one thread over their
260 * lifetime (a JS worker that migrates from one OS thread to another but shares
263 * Yes, this is an incompatible change, which prefigures the impending move to
264 * single-threaded objects and GC heaps.
266 extern js::Class js_ArgumentsClass
;
270 extern Class StrictArgumentsClass
;
272 struct ArgumentsData
{
280 JSObject::isNormalArguments() const
282 return getClass() == &js_ArgumentsClass
;
286 JSObject::isStrictArguments() const
288 return getClass() == &js::StrictArgumentsClass
;
292 JSObject::isArguments() const
294 return isNormalArguments() || isStrictArguments();
297 #define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
299 extern JS_PUBLIC_DATA(js::Class
) js_CallClass
;
300 extern JS_PUBLIC_DATA(js::Class
) js_FunctionClass
;
301 extern js::Class js_DeclEnvClass
;
304 JSObject::isCall() const
306 return getClass() == &js_CallClass
;
310 JSObject::isFunction() const
312 return getClass() == &js_FunctionClass
;
316 JSObject::getFunctionPrivate() const
318 JS_ASSERT(isFunction());
319 return reinterpret_cast<JSFunction
*>(getPrivate());
325 * Construct a call object for the given bindings. If this is a call object
326 * for a function invocation, callee should be the function being called.
327 * Otherwise it must be a call object for eval of strict mode code, and callee
331 NewCallObject(JSContext
*cx
, js::Bindings
*bindings
, JSObject
&scopeChain
, JSObject
*callee
);
334 * NB: jsapi.h and jsobj.h must be included before any call to this macro.
336 #define VALUE_IS_FUNCTION(cx, v) \
337 (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction())
339 static JS_ALWAYS_INLINE
bool
340 IsFunctionObject(const js::Value
&v
)
342 return v
.isObject() && v
.toObject().isFunction();
345 static JS_ALWAYS_INLINE
bool
346 IsFunctionObject(const js::Value
&v
, JSObject
**funobj
)
348 return v
.isObject() && (*funobj
= &v
.toObject())->isFunction();
351 static JS_ALWAYS_INLINE
bool
352 IsFunctionObject(const js::Value
&v
, JSFunction
**fun
)
355 bool b
= IsFunctionObject(v
, &funobj
);
357 *fun
= funobj
->getFunctionPrivate();
361 extern JS_ALWAYS_INLINE
bool
362 SameTraceType(const Value
&lhs
, const Value
&rhs
)
364 return SameType(lhs
, rhs
) &&
365 (lhs
.isPrimitive() ||
366 lhs
.toObject().isFunction() == rhs
.toObject().isFunction());
370 * Macro to access the private slot of the function object after the slot is
373 #define GET_FUNCTION_PRIVATE(cx, funobj) \
374 (JS_ASSERT((funobj)->isFunction()), \
375 (JSFunction *) (funobj)->getPrivate())
378 * Return true if this is a compiler-created internal function accessed by
379 * its own object. Such a function object must not be accessible to script
383 IsInternalFunctionObject(JSObject
*funobj
)
385 JS_ASSERT(funobj
->isFunction());
386 JSFunction
*fun
= (JSFunction
*) funobj
->getPrivate();
387 return funobj
== fun
&& (fun
->flags
& JSFUN_LAMBDA
) && !funobj
->getParent();
390 /* Valueified JS_IsConstructing. */
391 static JS_ALWAYS_INLINE
bool
392 IsConstructing(const Value
*vp
)
395 JSObject
*callee
= &JS_CALLEE(cx
, vp
).toObject();
396 if (callee
->isFunction()) {
397 JSFunction
*fun
= callee
->getFunctionPrivate();
398 JS_ASSERT((fun
->flags
& JSFUN_CONSTRUCTOR
) != 0);
400 JS_ASSERT(callee
->getClass()->construct
!= NULL
);
403 return vp
[1].isMagic();
406 static JS_ALWAYS_INLINE
bool
407 IsConstructing_PossiblyWithGivenThisObject(const Value
*vp
, JSObject
**ctorThis
)
410 JSObject
*callee
= &JS_CALLEE(cx
, vp
).toObject();
411 if (callee
->isFunction()) {
412 JSFunction
*fun
= callee
->getFunctionPrivate();
413 JS_ASSERT((fun
->flags
& JSFUN_CONSTRUCTOR
) != 0);
415 JS_ASSERT(callee
->getClass()->construct
!= NULL
);
418 bool isCtor
= vp
[1].isMagic();
420 *ctorThis
= vp
[1].getMagicObjectOrNullPayload();
425 GetFunctionNameBytes(JSContext
*cx
, JSFunction
*fun
, JSAutoByteString
*bytes
)
428 return bytes
->encode(cx
, ATOM_TO_STRING(fun
->atom
));
429 return js_anonymous_str
;
432 extern JS_FRIEND_API(bool)
433 IsBuiltinFunctionConstructor(JSFunction
*fun
);
436 * Preconditions: funobj->isInterpreted() && !funobj->isFunctionPrototype() &&
437 * !funobj->isBoundFunction(). This is sufficient to establish that funobj has
438 * a non-configurable non-method .prototype data property, thought it might not
439 * have been resolved yet, and its value could be anything.
441 * Return the shape of the .prototype property of funobj, resolving it if
442 * needed. On error, return NULL.
444 * This is not safe to call on trace because it defines properties, which can
445 * trigger lookups that could reenter.
448 LookupInterpretedFunctionPrototype(JSContext
*cx
, JSObject
*funobj
);
453 fun_toStringHelper(JSContext
*cx
, JSObject
*obj
, uintN indent
);
456 js_NewFunction(JSContext
*cx
, JSObject
*funobj
, js::Native native
, uintN nargs
,
457 uintN flags
, JSObject
*parent
, JSAtom
*atom
);
460 js_InitFunctionClass(JSContext
*cx
, JSObject
*obj
);
463 js_InitArgumentsClass(JSContext
*cx
, JSObject
*obj
);
466 js_TraceFunction(JSTracer
*trc
, JSFunction
*fun
);
469 js_FinalizeFunction(JSContext
*cx
, JSFunction
*fun
);
471 extern JSObject
* JS_FASTCALL
472 js_CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
,
476 CloneFunctionObject(JSContext
*cx
, JSFunction
*fun
, JSObject
*parent
)
480 if (!js_GetClassPrototype(cx
, parent
, JSProto_Function
, &proto
))
482 return js_CloneFunctionObject(cx
, fun
, parent
, proto
);
485 extern JSObject
* JS_FASTCALL
486 js_AllocFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSObject
*scopeChain
);
489 js_NewFlatClosure(JSContext
*cx
, JSFunction
*fun
, JSOp op
, size_t oplen
);
491 extern JS_REQUIRES_STACK JSObject
*
492 js_NewDebuggableFlatClosure(JSContext
*cx
, JSFunction
*fun
);
495 js_DefineFunction(JSContext
*cx
, JSObject
*obj
, jsid id
, js::Native native
,
496 uintN nargs
, uintN flags
);
499 * Flags for js_ValueToFunction and js_ReportIsNotFunction. We depend on the
500 * fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that
501 * with #if/#error in jsfun.c.
503 #define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT
504 #define JSV2F_SEARCH_STACK 0x10000
507 js_ValueToFunction(JSContext
*cx
, const js::Value
*vp
, uintN flags
);
510 js_ValueToFunctionObject(JSContext
*cx
, js::Value
*vp
, uintN flags
);
513 js_ValueToCallableObject(JSContext
*cx
, js::Value
*vp
, uintN flags
);
516 js_ReportIsNotFunction(JSContext
*cx
, const js::Value
*vp
, uintN flags
);
519 js_GetCallObject(JSContext
*cx
, JSStackFrame
*fp
);
521 extern JSObject
* JS_FASTCALL
522 js_CreateCallObjectOnTrace(JSContext
*cx
, JSFunction
*fun
, JSObject
*callee
, JSObject
*scopeChain
);
525 js_PutCallObject(JSContext
*cx
, JSStackFrame
*fp
);
527 extern JSBool JS_FASTCALL
528 js_PutCallObjectOnTrace(JSContext
*cx
, JSObject
*scopeChain
, uint32 nargs
,
529 js::Value
*argv
, uint32 nvars
, js::Value
*slots
);
534 GetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, js::Value
*vp
);
537 GetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, js::Value
*vp
);
540 * Slower version of js_GetCallVar used when call_resolve detects an attempt to
541 * leak an optimized closure via indirect or debugger eval.
544 GetCallVarChecked(JSContext
*cx
, JSObject
*obj
, jsid id
, js::Value
*vp
);
547 GetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, js::Value
*vp
);
550 SetCallArg(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, js::Value
*vp
);
553 SetCallVar(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, js::Value
*vp
);
556 SetCallUpvar(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, js::Value
*vp
);
561 js_GetArgsValue(JSContext
*cx
, JSStackFrame
*fp
, js::Value
*vp
);
564 js_GetArgsProperty(JSContext
*cx
, JSStackFrame
*fp
, jsid id
, js::Value
*vp
);
567 * Get the arguments object for the given frame. If the frame is strict mode
568 * code, its current arguments will be copied into the arguments object.
570 * NB: Callers *must* get the arguments object before any parameters are
571 * mutated when the frame is strict mode code! The emitter ensures this
572 * occurs for strict mode functions containing syntax which might mutate a
573 * named parameter by synthesizing an arguments access at the start of the
577 js_GetArgsObject(JSContext
*cx
, JSStackFrame
*fp
);
580 js_PutArgsObject(JSContext
*cx
, JSStackFrame
*fp
);
583 js_IsNamedLambda(JSFunction
*fun
) { return (fun
->flags
& JSFUN_LAMBDA
) && fun
->atom
; }
586 * Maximum supported value of arguments.length. It bounds the maximum number of
587 * arguments that can be supplied via the second (so-called |argArray|) param
588 * to Function.prototype.apply. This value also bounds the number of elements
589 * parsed in an array initialiser.
591 * The thread's stack is the limiting factor for this number. It is currently
592 * 2MB, which fits a little less than 2^19 arguments (once the stack frame,
593 * callstack, etc. are included). Pick a max args length that is a little less.
595 const uint32 JS_ARGS_LENGTH_MAX
= JS_BIT(19) - 1024;
598 * JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as an Int32
599 * Value. Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must be less than JSVAL_INT_MAX.
601 JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX
<= JS_BIT(30));
602 JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX
<< 1) | 1) <= JSVAL_INT_MAX
);
605 js_XDRFunctionObject(JSXDRState
*xdr
, JSObject
**objp
);
608 js_fun_apply(JSContext
*cx
, uintN argc
, js::Value
*vp
);
611 js_fun_call(JSContext
*cx
, uintN argc
, js::Value
*vp
);
613 #endif /* jsfun_h___ */