63 |
JSLocalNameMap *map; |
JSLocalNameMap *map; |
64 |
} JSLocalNames; |
} JSLocalNames; |
65 |
|
|
66 |
|
/* |
67 |
|
* The high two bits of JSFunction.flags encode whether the function is native |
68 |
|
* or interpreted, and if interpreted, what kind of optimized closure form (if |
69 |
|
* any) it might be. |
70 |
|
* |
71 |
|
* 00 not interpreted |
72 |
|
* 01 interpreted, neither flat nor null closure |
73 |
|
* 10 interpreted, flat closure |
74 |
|
* 11 interpreted, null closure |
75 |
|
* |
76 |
|
* FUN_FLAT_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset != 0. |
77 |
|
* FUN_NULL_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset == 0. |
78 |
|
* |
79 |
|
* FUN_INTERPRETED but not FUN_FLAT_CLOSURE and u.i.script->upvarsOffset != 0 |
80 |
|
* is an Algol-like function expression or nested function, i.e., a function |
81 |
|
* that never escapes upward or downward (heapward), and is only ever called. |
82 |
|
* |
83 |
|
* Finally, FUN_INTERPRETED and u.i.script->upvarsOffset == 0 could be either |
84 |
|
* a non-closure (a global function definition, or any function that uses no |
85 |
|
* outer names), or a closure of an escaping function that uses outer names |
86 |
|
* whose values can't be snapshot (because the outer names could be reassigned |
87 |
|
* after the closure is formed, or because assignments could not be analyzed |
88 |
|
* due to with or eval). |
89 |
|
* |
90 |
|
* Such a hard-case function must use JSOP_NAME, etc., and reify outer function |
91 |
|
* activations' call objects, etc. if it's not a global function. |
92 |
|
* |
93 |
|
* NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag |
94 |
|
* bit only, never stored in fun->flags. |
95 |
|
* |
96 |
|
* If we need more bits in the future, all flags for FUN_INTERPRETED functions |
97 |
|
* can move to u.i.script->flags. For now we use function flag bits to minimize |
98 |
|
* pointer-chasing. |
99 |
|
*/ |
100 |
|
#define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */ |
101 |
|
#define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native |
102 |
|
function; use FUN_TRCINFO if set, |
103 |
|
FUN_CLASP if unset */ |
104 |
|
#define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */ |
105 |
|
#define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */ |
106 |
|
#define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */ |
107 |
|
#define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure |
108 |
|
optimization level -- see above */ |
109 |
|
|
110 |
|
#define FUN_OBJECT(fun) (&(fun)->object) |
111 |
|
#define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK) |
112 |
|
#define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k)) |
113 |
|
#define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED) |
114 |
|
#define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE) |
115 |
|
#define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE) |
116 |
|
#define FUN_SLOW_NATIVE(fun) (!FUN_INTERPRETED(fun) && !((fun)->flags & JSFUN_FAST_NATIVE)) |
117 |
|
#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) |
118 |
|
#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) |
119 |
|
#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ |
120 |
|
? (JSFastNative) (fun)->u.n.native \ |
121 |
|
: NULL) |
122 |
|
#define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ |
123 |
|
? 0 \ |
124 |
|
: (fun)->nargs) |
125 |
|
#define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ |
126 |
|
fun->u.n.clasp) |
127 |
|
#define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ |
128 |
|
JS_ASSERT((fun)->flags & JSFUN_TRACEABLE), \ |
129 |
|
fun->u.n.trcinfo) |
130 |
|
|
131 |
struct JSFunction { |
struct JSFunction { |
132 |
JSObject object; /* GC'ed object header */ |
JSObject object; /* GC'ed object header */ |
133 |
uint16 nargs; /* maximum number of specified arguments, |
uint16 nargs; /* maximum number of specified arguments, |
138 |
uint16 extra; /* number of arg slots for local GC roots */ |
uint16 extra; /* number of arg slots for local GC roots */ |
139 |
uint16 spare; /* reserved for future use */ |
uint16 spare; /* reserved for future use */ |
140 |
JSNative native; /* native method pointer or null */ |
JSNative native; /* native method pointer or null */ |
141 |
union { |
JSClass *clasp; /* class of objects constructed |
142 |
JSClass *clasp; /* class of objects constructed |
by this function */ |
143 |
by this function */ |
JSTraceableNative *trcinfo; /* tracer metadata; can be first |
144 |
JSTraceableNative *trcinfo; /* tracer metadata; can be first |
element of array */ |
|
element of array */ |
|
|
} u; |
|
145 |
} n; |
} n; |
146 |
struct { |
struct { |
147 |
uint16 nvars; /* number of local variables */ |
uint16 nvars; /* number of local variables */ |
148 |
uint16 nupvars; /* number of upvars (computable from script |
uint16 nupvars; /* number of upvars (computable from script |
149 |
but here for faster access) */ |
but here for faster access) */ |
150 |
|
uint16 skipmin; /* net skip amount up (toward zero) from |
151 |
|
script->staticLevel to nearest upvar, |
152 |
|
including upvars in nested functions */ |
153 |
|
JSPackedBool wrapper; /* true if this function is a wrapper that |
154 |
|
rewrites bytecode optimized for a function |
155 |
|
judged non-escaping by the compiler, which |
156 |
|
then escaped via the debugger or a rogue |
157 |
|
indirect eval; if true, then this function |
158 |
|
object's proto is the wrapped object */ |
159 |
JSScript *script; /* interpreted bytecode descriptor or null */ |
JSScript *script; /* interpreted bytecode descriptor or null */ |
160 |
JSLocalNames names; /* argument and variable names */ |
JSLocalNames names; /* argument and variable names */ |
161 |
} i; |
} i; |
162 |
} u; |
} u; |
163 |
JSAtom *atom; /* name for diagnostics and decompiling */ |
JSAtom *atom; /* name for diagnostics and decompiling */ |
|
}; |
|
164 |
|
|
165 |
#define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native |
#ifdef __cplusplus |
166 |
function; use FUN_TRCINFO if set, |
bool optimizedClosure() { return FUN_KIND(this) > JSFUN_INTERPRETED; } |
167 |
FUN_CLASP if unset */ |
bool needsWrapper() { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; } |
168 |
#define JSFUN_EXPR_CLOSURE 0x4000 /* expression closure: function(x)x*x */ |
|
169 |
#define JSFUN_INTERPRETED 0x8000 /* use u.i if set, u.n if unset */ |
uintN countArgsAndVars() const { |
170 |
|
JS_ASSERT(FUN_INTERPRETED(this)); |
171 |
#define JSFUN_SCRIPT_OR_FAST_NATIVE (JSFUN_INTERPRETED | JSFUN_FAST_NATIVE) |
return nargs + u.i.nvars; |
172 |
|
} |
173 |
#define FUN_OBJECT(fun) (&(fun)->object) |
|
174 |
#define FUN_INTERPRETED(fun) ((fun)->flags & JSFUN_INTERPRETED) |
uintN countLocalNames() const { |
175 |
#define FUN_SLOW_NATIVE(fun) (!((fun)->flags & JSFUN_SCRIPT_OR_FAST_NATIVE)) |
JS_ASSERT(FUN_INTERPRETED(this)); |
176 |
#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) |
return countArgsAndVars() + u.i.nupvars; |
177 |
#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) |
} |
178 |
#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ |
|
179 |
? (JSFastNative) (fun)->u.n.native \ |
bool hasLocalNames() const { |
180 |
: NULL) |
JS_ASSERT(FUN_INTERPRETED(this)); |
181 |
#define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ |
return countLocalNames() != 0; |
182 |
? 0 \ |
} |
183 |
: (fun)->nargs) |
#endif |
184 |
#define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ |
}; |
|
JS_ASSERT(!((fun)->flags & JSFUN_TRACEABLE)), \ |
|
|
fun->u.n.u.clasp) |
|
|
#define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ |
|
|
JS_ASSERT((fun)->flags & JSFUN_TRACEABLE), \ |
|
|
fun->u.n.u.trcinfo) |
|
185 |
|
|
186 |
/* |
/* |
187 |
* Traceable native. This expands to a JSFunctionSpec initializer (like JS_FN |
* Traceable native. This expands to a JSFunctionSpec initializer (like JS_FN |
190 |
#ifdef JS_TRACER |
#ifdef JS_TRACER |
191 |
/* MSVC demands the intermediate (void *) cast here. */ |
/* MSVC demands the intermediate (void *) cast here. */ |
192 |
# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ |
# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ |
193 |
{name, (JSNative)(void *)(trcinfo), nargs, \ |
JS_FN(name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs, \ |
194 |
(flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE, 0} |
(flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE) |
195 |
#else |
#else |
196 |
# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ |
# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ |
197 |
JS_FN(name, fastcall, nargs, flags) |
JS_FN(name, fastcall, nargs, flags) |
199 |
|
|
200 |
extern JSClass js_ArgumentsClass; |
extern JSClass js_ArgumentsClass; |
201 |
extern JS_FRIEND_DATA(JSClass) js_CallClass; |
extern JS_FRIEND_DATA(JSClass) js_CallClass; |
202 |
|
extern JSClass js_DeclEnvClass; |
203 |
|
|
204 |
/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */ |
/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */ |
205 |
extern JS_FRIEND_DATA(JSClass) js_FunctionClass; |
extern JS_FRIEND_DATA(JSClass) js_FunctionClass; |
226 |
extern JSObject * |
extern JSObject * |
227 |
js_InitArgumentsClass(JSContext *cx, JSObject *obj); |
js_InitArgumentsClass(JSContext *cx, JSObject *obj); |
228 |
|
|
|
extern JSObject * |
|
|
js_InitCallClass(JSContext *cx, JSObject *obj); |
|
|
|
|
229 |
extern JSFunction * |
extern JSFunction * |
230 |
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, |
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, |
231 |
uintN flags, JSObject *parent, JSAtom *atom); |
uintN flags, JSObject *parent, JSAtom *atom); |
239 |
extern JSObject * |
extern JSObject * |
240 |
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent); |
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent); |
241 |
|
|
242 |
extern JSBool |
extern JS_REQUIRES_STACK JSObject * |
243 |
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object); |
js_NewFlatClosure(JSContext *cx, JSFunction *fun); |
244 |
|
|
245 |
|
extern JS_REQUIRES_STACK JSObject * |
246 |
|
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun); |
247 |
|
|
248 |
extern JSFunction * |
extern JSFunction * |
249 |
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, |
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, |
271 |
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags); |
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags); |
272 |
|
|
273 |
extern JSObject * |
extern JSObject * |
274 |
js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent); |
js_GetCallObject(JSContext *cx, JSStackFrame *fp); |
275 |
|
|
276 |
extern JS_FRIEND_API(JSBool) |
extern JS_FRIEND_API(JSBool) |
277 |
js_PutCallObject(JSContext *cx, JSStackFrame *fp); |
js_PutCallObject(JSContext *cx, JSStackFrame *fp); |
279 |
extern JSBool |
extern JSBool |
280 |
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp); |
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp); |
281 |
|
|
282 |
extern JSBool |
extern JS_REQUIRES_STACK JSBool |
283 |
js_GetCallVar(JSContext *cx, JSObject *obj, jsval id, jsval *vp); |
js_GetCallVar(JSContext *cx, JSObject *obj, jsval id, jsval *vp); |
284 |
|
|
285 |
|
/* |
286 |
|
* Slower version of js_GetCallVar used when call_resolve detects an attempt to |
287 |
|
* leak an optimized closure via indirect or debugger eval. |
288 |
|
*/ |
289 |
|
extern JS_REQUIRES_STACK JSBool |
290 |
|
js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp); |
291 |
|
|
292 |
extern JSBool |
extern JSBool |
293 |
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp); |
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp); |
294 |
|
|
302 |
js_PutArgsObject(JSContext *cx, JSStackFrame *fp); |
js_PutArgsObject(JSContext *cx, JSStackFrame *fp); |
303 |
|
|
304 |
extern JSBool |
extern JSBool |
305 |
js_XDRFunction(JSXDRState *xdr, JSObject **objp); |
js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp); |
306 |
|
|
307 |
typedef enum JSLocalKind { |
typedef enum JSLocalKind { |
308 |
JSLOCAL_NONE, |
JSLOCAL_NONE, |
312 |
JSLOCAL_UPVAR |
JSLOCAL_UPVAR |
313 |
} JSLocalKind; |
} JSLocalKind; |
314 |
|
|
|
#define JS_UPVAR_LOCAL_NAME_START(fun) ((fun)->nargs + (fun)->u.i.nvars) |
|
|
#define JS_GET_LOCAL_NAME_COUNT(fun) (JS_UPVAR_LOCAL_NAME_START(fun) + \ |
|
|
(fun)->u.i.nupvars) |
|
|
|
|
315 |
extern JSBool |
extern JSBool |
316 |
js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind); |
js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind); |
317 |
|
|
328 |
* Functions to work with local names as an array of words. |
* Functions to work with local names as an array of words. |
329 |
* |
* |
330 |
* js_GetLocalNameArray returns the array, or null if we are out of memory. |
* js_GetLocalNameArray returns the array, or null if we are out of memory. |
331 |
* This function must not be called when JS_GET_LOCAL_NAME_COUNT(fun) is zero. |
* This function must be called only when fun->hasLocalNames(). |
332 |
* |
* |
333 |
* The supplied pool is used to allocate the returned array, so the caller is |
* The supplied pool is used to allocate the returned array, so the caller is |
334 |
* obligated to mark and release to free it. |
* obligated to mark and release to free it. |
354 |
extern void |
extern void |
355 |
js_FreezeLocalNames(JSContext *cx, JSFunction *fun); |
js_FreezeLocalNames(JSContext *cx, JSFunction *fun); |
356 |
|
|
357 |
extern JSBool |
extern JS_REQUIRES_STACK JSBool |
358 |
js_fun_apply(JSContext *cx, uintN argc, jsval *vp); |
js_fun_apply(JSContext *cx, uintN argc, jsval *vp); |
359 |
|
|
360 |
extern JSBool |
extern JS_REQUIRES_STACK JSBool |
361 |
js_fun_call(JSContext *cx, uintN argc, jsval *vp); |
js_fun_call(JSContext *cx, uintN argc, jsval *vp); |
362 |
|
|
363 |
|
|