1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
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.
23 : *
24 : * Contributor(s):
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef jsfun_h___
41 : #define jsfun_h___
42 : /*
43 : * JS function definitions.
44 : */
45 : #include "jsprvtd.h"
46 : #include "jspubtd.h"
47 : #include "jsobj.h"
48 : #include "jsatom.h"
49 : #include "jsscript.h"
50 : #include "jsstr.h"
51 :
52 : #include "gc/Barrier.h"
53 :
54 : /*
55 : * The high two bits of JSFunction.flags encode whether the function is native
56 : * or interpreted, and if interpreted, what kind of optimized closure form (if
57 : * any) it might be.
58 : *
59 : * 00 not interpreted
60 : * 01 interpreted, neither flat nor null closure
61 : * 10 interpreted, flat closure
62 : * 11 interpreted, null closure
63 : *
64 : * isFlatClosure() implies isInterpreted() and u.i.script->upvarsOffset != 0.
65 : * isNullClosure() implies isInterpreted() and u.i.script->upvarsOffset == 0.
66 : *
67 : * isInterpreted() but not isFlatClosure() and u.i.script->upvarsOffset != 0
68 : * is an Algol-like function expression or nested function, i.e., a function
69 : * that never escapes upward or downward (heapward), and is only ever called.
70 : *
71 : * Finally, isInterpreted() and u.i.script->upvarsOffset == 0 could be either
72 : * a non-closure (a global function definition, or any function that uses no
73 : * outer names), or a closure of an escaping function that uses outer names
74 : * whose values can't be snapshot (because the outer names could be reassigned
75 : * after the closure is formed, or because assignments could not be analyzed
76 : * due to with or eval).
77 : *
78 : * Such a hard-case function must use JSOP_NAME, etc., and reify outer function
79 : * activations' call objects, etc. if it's not a global function.
80 : *
81 : * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
82 : * bit only, never stored in fun->flags.
83 : *
84 : * If we need more bits in the future, all flags for interpreted functions can
85 : * move to u.i.script->flags. For now we use function flag bits to minimize
86 : * pointer-chasing.
87 : */
88 : #define JSFUN_JOINABLE 0x0001 /* function is null closure that does not
89 : appear to call itself via its own name
90 : or arguments.callee */
91 :
92 : #define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
93 : global object */
94 :
95 : #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
96 : #define JSFUN_EXTENDED 0x2000 /* structure is FunctionExtended */
97 : #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
98 : #define JSFUN_FLAT_CLOSURE 0x8000 /* flat (aka "display") closure */
99 : #define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
100 : #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
101 : optimization level -- see above */
102 :
103 : namespace js { class FunctionExtended; }
104 :
105 : struct JSFunction : public JSObject
106 : {
107 : uint16_t nargs; /* maximum number of specified arguments,
108 : reflected as f.length/f.arity */
109 : uint16_t flags; /* flags, see JSFUN_* below and in jsapi.h */
110 : union U {
111 : struct Native {
112 : js::Native native; /* native method pointer or null */
113 : js::Class *clasp; /* class of objects constructed
114 : by this function */
115 : } n;
116 : struct Scripted {
117 : JSScript *script_; /* interpreted bytecode descriptor or null;
118 : use the accessor! */
119 : JSObject *env_; /* environment for new activations;
120 : use the accessor! */
121 : } i;
122 : void *nativeOrScript;
123 : } u;
124 : JSAtom *atom; /* name for diagnostics and decompiling */
125 :
126 : bool optimizedClosure() const { return kind() > JSFUN_INTERPRETED; }
127 1561610332 : bool isInterpreted() const { return kind() >= JSFUN_INTERPRETED; }
128 53250410 : bool isNative() const { return !isInterpreted(); }
129 220674 : bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
130 44978939 : bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
131 3591705 : bool isNullClosure() const { return kind() == JSFUN_NULL_CLOSURE; }
132 66035057 : bool isFlatClosure() const { return kind() == JSFUN_FLAT_CLOSURE; }
133 13326963 : bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
134 24513544 : bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
135 :
136 1633258556 : uint16_t kind() const { return flags & JSFUN_KINDMASK; }
137 807911 : void setKind(uint16_t k) {
138 807911 : JS_ASSERT(!(k & ~JSFUN_KINDMASK));
139 807911 : flags = (flags & ~JSFUN_KINDMASK) | k;
140 807911 : }
141 :
142 : /* Returns the strictness of this function, which must be interpreted. */
143 : inline bool inStrictMode() const;
144 :
145 989222 : void setArgCount(uint16_t nargs) {
146 989222 : JS_ASSERT(this->nargs == 0);
147 989222 : this->nargs = nargs;
148 989222 : }
149 :
150 : /* uint16_t representation bounds number of call object dynamic slots. */
151 : enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
152 :
153 : #define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1)))
154 : #define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0)
155 :
156 : bool mightEscape() const {
157 : return isInterpreted() && (isFlatClosure() || !script()->bindings.hasUpvars());
158 : }
159 :
160 778112 : bool joinable() const {
161 778112 : return flags & JSFUN_JOINABLE;
162 : }
163 :
164 : /*
165 : * For an interpreted function, accessors for the initial scope object of
166 : * activations (stack frames) of the function.
167 : */
168 : inline JSObject *environment() const;
169 : inline void setEnvironment(JSObject *obj);
170 : inline void initEnvironment(JSObject *obj);
171 :
172 47701 : static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
173 :
174 : inline void setJoinable();
175 :
176 1303869562 : js::HeapPtrScript &script() const {
177 1303869562 : JS_ASSERT(isInterpreted());
178 1303869562 : return *(js::HeapPtrScript *)&u.i.script_;
179 : }
180 :
181 : inline void setScript(JSScript *script_);
182 : inline void initScript(JSScript *script_);
183 :
184 2194657 : JSScript *maybeScript() const {
185 2194657 : return isInterpreted() ? script().get() : NULL;
186 : }
187 :
188 400821 : JSNative native() const {
189 400821 : JS_ASSERT(isNative());
190 400821 : return u.n.native;
191 : }
192 :
193 365745 : JSNative maybeNative() const {
194 365745 : return isInterpreted() ? NULL : native();
195 : }
196 :
197 5680 : static unsigned offsetOfNativeOrScript() {
198 : JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.script_));
199 : JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript));
200 5680 : return offsetof(JSFunction, u.nativeOrScript);
201 : }
202 :
203 : js::Class *getConstructorClass() const {
204 : JS_ASSERT(isNative());
205 : return u.n.clasp;
206 : }
207 :
208 390957 : void setConstructorClass(js::Class *clasp) {
209 390957 : JS_ASSERT(isNative());
210 390957 : u.n.clasp = clasp;
211 390957 : }
212 :
213 : #if JS_BITS_PER_WORD == 32
214 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2;
215 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4;
216 : #else
217 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4;
218 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8;
219 : #endif
220 :
221 : inline void trace(JSTracer *trc);
222 :
223 : /* Bound function accessors. */
224 :
225 : inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
226 : const js::Value *args, unsigned argslen);
227 :
228 : inline JSObject *getBoundFunctionTarget() const;
229 : inline const js::Value &getBoundFunctionThis() const;
230 : inline const js::Value &getBoundFunctionArgument(unsigned which) const;
231 : inline size_t getBoundFunctionArgumentCount() const;
232 :
233 : private:
234 : inline js::FunctionExtended *toExtended();
235 : inline const js::FunctionExtended *toExtended() const;
236 :
237 135610672 : inline bool isExtended() const {
238 : JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
239 135610672 : JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
240 135610672 : return !!(flags & JSFUN_EXTENDED);
241 : }
242 :
243 : public:
244 : /* Accessors for data stored in extended functions. */
245 :
246 : inline void initializeExtended();
247 :
248 : inline void setExtendedSlot(size_t which, const js::Value &val);
249 : inline const js::Value &getExtendedSlot(size_t which) const;
250 :
251 : /*
252 : * Flat closures with one or more upvars snapshot the upvars' values
253 : * into a vector of js::Values referenced from here. This is a private
254 : * pointer but is set only at creation and does not need to be barriered.
255 : */
256 : static const uint32_t FLAT_CLOSURE_UPVARS_SLOT = 0;
257 :
258 : static inline size_t getFlatClosureUpvarsOffset();
259 :
260 : inline js::Value getFlatClosureUpvar(uint32_t i) const;
261 : inline void setFlatClosureUpvar(uint32_t i, const js::Value &v);
262 : inline void initFlatClosureUpvar(uint32_t i, const js::Value &v);
263 :
264 : private:
265 : inline bool hasFlatClosureUpvars() const;
266 : inline js::HeapValue *getFlatClosureUpvars() const;
267 : public:
268 :
269 : /* See comments in fun_finalize. */
270 : inline void finalizeUpvars();
271 :
272 : /* Slot holding associated method property, needed for foo.caller handling. */
273 : static const uint32_t METHOD_PROPERTY_SLOT = 0;
274 :
275 : /* For cloned methods, slot holding the object this was cloned as a property from. */
276 : static const uint32_t METHOD_OBJECT_SLOT = 1;
277 :
278 : /* Whether this is a function cloned from a method. */
279 : inline bool isClonedMethod() const;
280 :
281 : /* For a cloned method, pointer to the object the method was cloned for. */
282 : inline JSObject *methodObj() const;
283 : inline void setMethodObj(JSObject& obj);
284 :
285 : /*
286 : * Method name imputed from property uniquely assigned to or initialized,
287 : * where the function does not need to be cloned to carry a scope chain or
288 : * flattened upvars. This is set on both the original and cloned function.
289 : */
290 : inline JSAtom *methodAtom() const;
291 : inline void setMethodAtom(JSAtom *atom);
292 :
293 : /*
294 : * Measures things hanging off this JSFunction that are counted by the
295 : * |miscSize| argument in JSObject::sizeOfExcludingThis().
296 : */
297 : size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const;
298 :
299 : private:
300 : /*
301 : * These member functions are inherited from JSObject, but should never be applied to
302 : * a value statically known to be a JSFunction.
303 : */
304 : inline JSFunction *toFunction() MOZ_DELETE;
305 : inline const JSFunction *toFunction() const MOZ_DELETE;
306 : };
307 :
308 : inline JSFunction *
309 262507105 : JSObject::toFunction()
310 : {
311 262507105 : JS_ASSERT(JS_ObjectIsFunction(NULL, this));
312 262507105 : return static_cast<JSFunction *>(this);
313 : }
314 :
315 : inline const JSFunction *
316 16037 : JSObject::toFunction() const
317 : {
318 16037 : JS_ASSERT(JS_ObjectIsFunction(NULL, const_cast<JSObject *>(this)));
319 16037 : return static_cast<const JSFunction *>(this);
320 : }
321 :
322 : extern JSString *
323 : fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent);
324 :
325 : extern JSFunction *
326 : js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, unsigned nargs,
327 : unsigned flags, js::HandleObject parent, JSAtom *atom,
328 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
329 :
330 : extern JSFunction * JS_FASTCALL
331 : js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JSObject *proto,
332 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
333 :
334 : extern JSFunction * JS_FASTCALL
335 : js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain);
336 :
337 : extern JSFunction *
338 : js_NewFlatClosure(JSContext *cx, JSFunction *fun);
339 :
340 : extern JSFunction *
341 : js_DefineFunction(JSContext *cx, js::HandleObject obj, jsid id, JSNative native,
342 : unsigned nargs, unsigned flags,
343 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
344 :
345 : /*
346 : * Flags for js_ValueToFunction and js_ReportIsNotFunction.
347 : */
348 : #define JSV2F_CONSTRUCT INITIAL_CONSTRUCT
349 : #define JSV2F_SEARCH_STACK 0x10000
350 :
351 : extern JSFunction *
352 : js_ValueToFunction(JSContext *cx, const js::Value *vp, unsigned flags);
353 :
354 : extern JSObject *
355 : js_ValueToCallableObject(JSContext *cx, js::Value *vp, unsigned flags);
356 :
357 : extern void
358 : js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, unsigned flags);
359 :
360 : extern void
361 : js_PutCallObject(js::StackFrame *fp);
362 :
363 : namespace js {
364 :
365 : /*
366 : * Function extended with reserved slots for use by various kinds of functions.
367 : * Most functions do not have these extensions, but enough are that efficient
368 : * storage is required (no malloc'ed reserved slots).
369 : */
370 : class FunctionExtended : public JSFunction
371 : {
372 : friend struct JSFunction;
373 :
374 : /* Reserved slots available for storage by particular native functions. */
375 : HeapValue extendedSlots[2];
376 : };
377 :
378 : } // namespace js
379 :
380 : inline js::FunctionExtended *
381 33492248 : JSFunction::toExtended()
382 : {
383 33492248 : JS_ASSERT(isExtended());
384 33492248 : return static_cast<js::FunctionExtended *>(this);
385 : }
386 :
387 : inline const js::FunctionExtended *
388 49168820 : JSFunction::toExtended() const
389 : {
390 49168820 : JS_ASSERT(isExtended());
391 49168820 : return static_cast<const js::FunctionExtended *>(this);
392 : }
393 :
394 : /*
395 : * Get the arguments object for the given frame. If the frame is strict mode
396 : * code, its current arguments will be copied into the arguments object.
397 : *
398 : * NB: Callers *must* get the arguments object before any parameters are
399 : * mutated when the frame is strict mode code! The emitter ensures this
400 : * occurs for strict mode functions containing syntax which might mutate a
401 : * named parameter by synthesizing an arguments access at the start of the
402 : * function.
403 : */
404 : extern js::ArgumentsObject *
405 : js_GetArgsObject(JSContext *cx, js::StackFrame *fp);
406 :
407 : extern void
408 : js_PutArgsObject(js::StackFrame *fp);
409 :
410 : inline bool
411 704675 : js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
412 :
413 : namespace js {
414 :
415 : extern JSBool
416 : XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
417 :
418 : } /* namespace js */
419 :
420 : extern JSBool
421 : js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
422 :
423 : extern JSBool
424 : js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
425 :
426 : #endif /* jsfun_h___ */
|