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 : // 0x0001 was JSFUN_JOINABLE, but was deleted for bug 739808.
89 : #define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
90 : global object */
91 :
92 : #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
93 : #define JSFUN_EXTENDED 0x2000 /* structure is FunctionExtended */
94 : #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
95 : #define JSFUN_FLAT_CLOSURE 0x8000 /* flat (aka "display") closure */
96 : #define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
97 : #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
98 : optimization level -- see above */
99 :
100 : namespace js { class FunctionExtended; }
101 :
102 : struct JSFunction : public JSObject
103 : {
104 : uint16_t nargs; /* maximum number of specified arguments,
105 : reflected as f.length/f.arity */
106 : uint16_t flags; /* flags, see JSFUN_* below and in jsapi.h */
107 : union U {
108 : struct Native {
109 : js::Native native; /* native method pointer or null */
110 : js::Class *clasp; /* class of objects constructed
111 : by this function */
112 : } n;
113 : struct Scripted {
114 : JSScript *script_; /* interpreted bytecode descriptor or null;
115 : use the accessor! */
116 : JSObject *env_; /* environment for new activations;
117 : use the accessor! */
118 : } i;
119 : void *nativeOrScript;
120 : } u;
121 : JSAtom *atom; /* name for diagnostics and decompiling */
122 :
123 : bool optimizedClosure() const { return kind() > JSFUN_INTERPRETED; }
124 1755728364 : bool isInterpreted() const { return kind() >= JSFUN_INTERPRETED; }
125 51426890 : bool isNative() const { return !isInterpreted(); }
126 220923 : bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
127 44956295 : bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
128 2200455 : bool isNullClosure() const { return kind() == JSFUN_NULL_CLOSURE; }
129 65804583 : bool isFlatClosure() const { return kind() == JSFUN_FLAT_CLOSURE; }
130 13319219 : bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
131 24247117 : bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
132 :
133 1825758607 : uint16_t kind() const { return flags & JSFUN_KINDMASK; }
134 809715 : void setKind(uint16_t k) {
135 809715 : JS_ASSERT(!(k & ~JSFUN_KINDMASK));
136 809715 : flags = (flags & ~JSFUN_KINDMASK) | k;
137 809715 : }
138 :
139 : /* Returns the strictness of this function, which must be interpreted. */
140 : inline bool inStrictMode() const;
141 :
142 991083 : void setArgCount(uint16_t nargs) {
143 991083 : JS_ASSERT(this->nargs == 0);
144 991083 : this->nargs = nargs;
145 991083 : }
146 :
147 : /* uint16_t representation bounds number of call object dynamic slots. */
148 : enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
149 :
150 : #define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1)))
151 : #define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0)
152 :
153 : bool mightEscape() const {
154 : return isInterpreted() && (isFlatClosure() || !script()->bindings.hasUpvars());
155 : }
156 :
157 606 : bool joinable() const {
158 606 : return false;
159 : }
160 :
161 : /*
162 : * For an interpreted function, accessors for the initial scope object of
163 : * activations (stack frames) of the function.
164 : */
165 : inline JSObject *environment() const;
166 : inline void setEnvironment(JSObject *obj);
167 : inline void initEnvironment(JSObject *obj);
168 :
169 47585 : static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
170 :
171 1501606268 : js::HeapPtrScript &script() const {
172 1501606268 : JS_ASSERT(isInterpreted());
173 1501606268 : return *(js::HeapPtrScript *)&u.i.script_;
174 : }
175 :
176 : inline void setScript(JSScript *script_);
177 : inline void initScript(JSScript *script_);
178 :
179 1868089 : JSScript *maybeScript() const {
180 1868089 : return isInterpreted() ? script().get() : NULL;
181 : }
182 :
183 388490 : JSNative native() const {
184 388490 : JS_ASSERT(isNative());
185 388490 : return u.n.native;
186 : }
187 :
188 351473 : JSNative maybeNative() const {
189 351473 : return isInterpreted() ? NULL : native();
190 : }
191 :
192 5719 : static unsigned offsetOfNativeOrScript() {
193 : JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.script_));
194 : JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript));
195 5719 : return offsetof(JSFunction, u.nativeOrScript);
196 : }
197 :
198 : js::Class *getConstructorClass() const {
199 : JS_ASSERT(isNative());
200 : return u.n.clasp;
201 : }
202 :
203 391372 : void setConstructorClass(js::Class *clasp) {
204 391372 : JS_ASSERT(isNative());
205 391372 : u.n.clasp = clasp;
206 391372 : }
207 :
208 : #if JS_BITS_PER_WORD == 32
209 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2;
210 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4;
211 : #else
212 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4;
213 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8;
214 : #endif
215 :
216 : inline void trace(JSTracer *trc);
217 :
218 : /* Bound function accessors. */
219 :
220 : inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
221 : const js::Value *args, unsigned argslen);
222 :
223 : inline JSObject *getBoundFunctionTarget() const;
224 : inline const js::Value &getBoundFunctionThis() const;
225 : inline const js::Value &getBoundFunctionArgument(unsigned which) const;
226 : inline size_t getBoundFunctionArgumentCount() const;
227 :
228 : private:
229 : inline js::FunctionExtended *toExtended();
230 : inline const js::FunctionExtended *toExtended() const;
231 :
232 132433030 : inline bool isExtended() const {
233 : JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
234 132433030 : JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
235 132433030 : return !!(flags & JSFUN_EXTENDED);
236 : }
237 :
238 : public:
239 : /* Accessors for data stored in extended functions. */
240 :
241 : inline void initializeExtended();
242 :
243 : inline void setExtendedSlot(size_t which, const js::Value &val);
244 : inline const js::Value &getExtendedSlot(size_t which) const;
245 :
246 : /*
247 : * Flat closures with one or more upvars snapshot the upvars' values
248 : * into a vector of js::Values referenced from here. This is a private
249 : * pointer but is set only at creation and does not need to be barriered.
250 : */
251 : static const uint32_t FLAT_CLOSURE_UPVARS_SLOT = 0;
252 :
253 : static inline size_t getFlatClosureUpvarsOffset();
254 :
255 : inline js::Value getFlatClosureUpvar(uint32_t i) const;
256 : inline void setFlatClosureUpvar(uint32_t i, const js::Value &v);
257 : inline void initFlatClosureUpvar(uint32_t i, const js::Value &v);
258 :
259 : private:
260 : inline bool hasFlatClosureUpvars() const;
261 : inline js::HeapValue *getFlatClosureUpvars() const;
262 : public:
263 :
264 : /* See comments in fun_finalize. */
265 : inline void finalizeUpvars();
266 :
267 : /* Slot holding associated method property, needed for foo.caller handling. */
268 : static const uint32_t METHOD_PROPERTY_SLOT = 0;
269 :
270 : /* For cloned methods, slot holding the object this was cloned as a property from. */
271 : static const uint32_t METHOD_OBJECT_SLOT = 1;
272 :
273 : /* Whether this is a function cloned from a method. */
274 : inline bool isClonedMethod() const;
275 :
276 : /* For a cloned method, pointer to the object the method was cloned for. */
277 : inline JSObject *methodObj() const;
278 : inline void setMethodObj(JSObject& obj);
279 :
280 : /*
281 : * Method name imputed from property uniquely assigned to or initialized,
282 : * where the function does not need to be cloned to carry a scope chain or
283 : * flattened upvars. This is set on both the original and cloned function.
284 : */
285 : inline JSAtom *methodAtom() const;
286 : inline void setMethodAtom(JSAtom *atom);
287 :
288 : /*
289 : * Measures things hanging off this JSFunction that are counted by the
290 : * |miscSize| argument in JSObject::sizeOfExcludingThis().
291 : */
292 : size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const;
293 :
294 : private:
295 : /*
296 : * These member functions are inherited from JSObject, but should never be applied to
297 : * a value statically known to be a JSFunction.
298 : */
299 : inline JSFunction *toFunction() MOZ_DELETE;
300 : inline const JSFunction *toFunction() const MOZ_DELETE;
301 : };
302 :
303 : inline JSFunction *
304 258430158 : JSObject::toFunction()
305 : {
306 258430158 : JS_ASSERT(JS_ObjectIsFunction(NULL, this));
307 258430158 : return static_cast<JSFunction *>(this);
308 : }
309 :
310 : inline const JSFunction *
311 16046 : JSObject::toFunction() const
312 : {
313 16046 : JS_ASSERT(JS_ObjectIsFunction(NULL, const_cast<JSObject *>(this)));
314 16046 : return static_cast<const JSFunction *>(this);
315 : }
316 :
317 : extern JSString *
318 : fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent);
319 :
320 : extern JSFunction *
321 : js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, unsigned nargs,
322 : unsigned flags, js::HandleObject parent, JSAtom *atom,
323 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
324 :
325 : extern JSFunction * JS_FASTCALL
326 : js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JSObject *proto,
327 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
328 :
329 : extern JSFunction * JS_FASTCALL
330 : js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain);
331 :
332 : extern JSFunction *
333 : js_NewFlatClosure(JSContext *cx, JSFunction *fun);
334 :
335 : extern JSFunction *
336 : js_DefineFunction(JSContext *cx, js::HandleObject obj, jsid id, JSNative native,
337 : unsigned nargs, unsigned flags,
338 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
339 :
340 : /*
341 : * Flags for js_ValueToFunction and js_ReportIsNotFunction.
342 : */
343 : #define JSV2F_CONSTRUCT INITIAL_CONSTRUCT
344 : #define JSV2F_SEARCH_STACK 0x10000
345 :
346 : extern JSFunction *
347 : js_ValueToFunction(JSContext *cx, const js::Value *vp, unsigned flags);
348 :
349 : extern JSObject *
350 : js_ValueToCallableObject(JSContext *cx, js::Value *vp, unsigned flags);
351 :
352 : extern void
353 : js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, unsigned flags);
354 :
355 : extern void
356 : js_PutCallObject(js::StackFrame *fp);
357 :
358 : namespace js {
359 :
360 : /*
361 : * Function extended with reserved slots for use by various kinds of functions.
362 : * Most functions do not have these extensions, but enough are that efficient
363 : * storage is required (no malloc'ed reserved slots).
364 : */
365 : class FunctionExtended : public JSFunction
366 : {
367 : friend struct JSFunction;
368 :
369 : /* Reserved slots available for storage by particular native functions. */
370 : HeapValue extendedSlots[2];
371 : };
372 :
373 : } // namespace js
374 :
375 : inline js::FunctionExtended *
376 33482676 : JSFunction::toExtended()
377 : {
378 33482676 : JS_ASSERT(isExtended());
379 33482676 : return static_cast<js::FunctionExtended *>(this);
380 : }
381 :
382 : inline const js::FunctionExtended *
383 46245276 : JSFunction::toExtended() const
384 : {
385 46245276 : JS_ASSERT(isExtended());
386 46245276 : return static_cast<const js::FunctionExtended *>(this);
387 : }
388 :
389 : /*
390 : * Get the arguments object for the given frame. If the frame is strict mode
391 : * code, its current arguments will be copied into the arguments object.
392 : *
393 : * NB: Callers *must* get the arguments object before any parameters are
394 : * mutated when the frame is strict mode code! The emitter ensures this
395 : * occurs for strict mode functions containing syntax which might mutate a
396 : * named parameter by synthesizing an arguments access at the start of the
397 : * function.
398 : */
399 : extern js::ArgumentsObject *
400 : js_GetArgsObject(JSContext *cx, js::StackFrame *fp);
401 :
402 : extern void
403 : js_PutArgsObject(js::StackFrame *fp);
404 :
405 : inline bool
406 704274 : js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
407 :
408 : namespace js {
409 :
410 : extern JSBool
411 : XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
412 :
413 : } /* namespace js */
414 :
415 : extern JSBool
416 : js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
417 :
418 : extern JSBool
419 : js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
420 :
421 : #endif /* jsfun_h___ */
|