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, not null closure
61 : * 11 interpreted, null closure
62 : *
63 : * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
64 : * bit only, never stored in fun->flags.
65 : *
66 : * If we need more bits in the future, all flags for interpreted functions can
67 : * move to u.i.script->flags. For now we use function flag bits to minimize
68 : * pointer-chasing.
69 : */
70 : #define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
71 : global object */
72 :
73 : #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
74 : #define JSFUN_EXTENDED 0x2000 /* structure is FunctionExtended */
75 : #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.native */
76 : #define JSFUN_NULL_CLOSURE 0x8000 /* null closure entrains no scope chain */
77 : #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
78 : optimization level -- see above */
79 :
80 : namespace js { class FunctionExtended; }
81 :
82 : struct JSFunction : public JSObject
83 : {
84 : uint16_t nargs; /* maximum number of specified arguments,
85 : reflected as f.length/f.arity */
86 : uint16_t flags; /* flags, see JSFUN_* below and in jsapi.h */
87 : union U {
88 : js::Native native; /* native method pointer or null */
89 : struct Scripted {
90 : JSScript *script_; /* interpreted bytecode descriptor or null;
91 : use the accessor! */
92 : JSObject *env_; /* environment for new activations;
93 : use the accessor! */
94 : } i;
95 : void *nativeOrScript;
96 : } u;
97 : js::HeapPtrAtom atom; /* name for diagnostics and decompiling */
98 :
99 : bool optimizedClosure() const { return kind() > JSFUN_INTERPRETED; }
100 1390850588 : bool isInterpreted() const { return kind() >= JSFUN_INTERPRETED; }
101 36140374 : bool isNative() const { return !isInterpreted(); }
102 217580 : bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
103 32819539 : bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
104 1066085 : bool isNullClosure() const { return kind() == JSFUN_NULL_CLOSURE; }
105 10655467 : bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
106 17004254 : bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
107 :
108 1392233566 : uint16_t kind() const { return flags & JSFUN_KINDMASK; }
109 131003 : void setKind(uint16_t k) {
110 131003 : JS_ASSERT(!(k & ~JSFUN_KINDMASK));
111 131003 : flags = (flags & ~JSFUN_KINDMASK) | k;
112 131003 : }
113 :
114 : /* Returns the strictness of this function, which must be interpreted. */
115 : inline bool inStrictMode() const;
116 :
117 167182 : void setArgCount(uint16_t nargs) {
118 167182 : JS_ASSERT(this->nargs == 0);
119 167182 : this->nargs = nargs;
120 167182 : }
121 :
122 : /* uint16_t representation bounds number of call object dynamic slots. */
123 : enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
124 :
125 : #define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1)))
126 : #define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0)
127 :
128 : /*
129 : * For an interpreted function, accessors for the initial scope object of
130 : * activations (stack frames) of the function.
131 : */
132 : inline JSObject *environment() const;
133 : inline void setEnvironment(JSObject *obj);
134 : inline void initEnvironment(JSObject *obj);
135 :
136 13848 : static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
137 :
138 1232152902 : js::HeapPtrScript &script() const {
139 1232152902 : JS_ASSERT(isInterpreted());
140 1232152902 : return *(js::HeapPtrScript *)&u.i.script_;
141 : }
142 :
143 : inline void setScript(JSScript *script_);
144 : inline void initScript(JSScript *script_);
145 :
146 476 : JSScript *maybeScript() const {
147 476 : return isInterpreted() ? script().get() : NULL;
148 : }
149 :
150 14953801 : JSNative native() const {
151 14953801 : JS_ASSERT(isNative());
152 14953801 : return u.native;
153 : }
154 :
155 494910 : JSNative maybeNative() const {
156 494910 : return isInterpreted() ? NULL : native();
157 : }
158 :
159 4235 : static unsigned offsetOfNativeOrScript() {
160 : JS_STATIC_ASSERT(offsetof(U, native) == offsetof(U, i.script_));
161 : JS_STATIC_ASSERT(offsetof(U, native) == offsetof(U, nativeOrScript));
162 4235 : return offsetof(JSFunction, u.nativeOrScript);
163 : }
164 :
165 : #if JS_BITS_PER_WORD == 32
166 : # ifdef JS_THREADSAFE
167 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2_BACKGROUND;
168 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
169 : # else
170 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2;
171 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4;
172 : # endif
173 : #else
174 : # ifdef JS_THREADSAFE
175 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
176 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND;
177 : # else
178 : static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4;
179 : static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8;
180 : # endif
181 : #endif
182 :
183 : inline void trace(JSTracer *trc);
184 :
185 : /* Bound function accessors. */
186 :
187 : inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
188 : const js::Value *args, unsigned argslen);
189 :
190 : inline JSObject *getBoundFunctionTarget() const;
191 : inline const js::Value &getBoundFunctionThis() const;
192 : inline const js::Value &getBoundFunctionArgument(unsigned which) const;
193 : inline size_t getBoundFunctionArgumentCount() const;
194 :
195 : private:
196 : inline js::FunctionExtended *toExtended();
197 : inline const js::FunctionExtended *toExtended() const;
198 :
199 18616857 : inline bool isExtended() const {
200 : JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
201 18616857 : JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
202 18616857 : return !!(flags & JSFUN_EXTENDED);
203 : }
204 :
205 : public:
206 : /* Accessors for data stored in extended functions. */
207 : inline void initializeExtended();
208 : inline void setExtendedSlot(size_t which, const js::Value &val);
209 : inline const js::Value &getExtendedSlot(size_t which) const;
210 :
211 : private:
212 : /*
213 : * These member functions are inherited from JSObject, but should never be applied to
214 : * a value statically known to be a JSFunction.
215 : */
216 : inline JSFunction *toFunction() MOZ_DELETE;
217 : inline const JSFunction *toFunction() const MOZ_DELETE;
218 : };
219 :
220 : inline JSFunction *
221 138113956 : JSObject::toFunction()
222 : {
223 138113956 : JS_ASSERT(JS_ObjectIsFunction(NULL, this));
224 138113956 : return static_cast<JSFunction *>(this);
225 : }
226 :
227 : inline const JSFunction *
228 : JSObject::toFunction() const
229 : {
230 : JS_ASSERT(JS_ObjectIsFunction(NULL, const_cast<JSObject *>(this)));
231 : return static_cast<const JSFunction *>(this);
232 : }
233 :
234 : extern JSString *
235 : fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent);
236 :
237 : extern JSFunction *
238 : js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, unsigned nargs,
239 : unsigned flags, js::HandleObject parent, JSAtom *atom,
240 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
241 :
242 : extern JSFunction * JS_FASTCALL
243 : js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JSObject *proto,
244 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
245 :
246 : extern JSFunction *
247 : js_DefineFunction(JSContext *cx, js::HandleObject obj, jsid id, JSNative native,
248 : unsigned nargs, unsigned flags,
249 : js::gc::AllocKind kind = JSFunction::FinalizeKind);
250 :
251 : /*
252 : * Flags for js_ValueToFunction and js_ReportIsNotFunction.
253 : */
254 : #define JSV2F_CONSTRUCT INITIAL_CONSTRUCT
255 : #define JSV2F_SEARCH_STACK 0x10000
256 :
257 : extern JSFunction *
258 : js_ValueToFunction(JSContext *cx, const js::Value *vp, unsigned flags);
259 :
260 : extern JSObject *
261 : js_ValueToCallableObject(JSContext *cx, js::Value *vp, unsigned flags);
262 :
263 : extern void
264 : js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, unsigned flags);
265 :
266 : extern void
267 : js_PutCallObject(js::StackFrame *fp);
268 :
269 : namespace js {
270 :
271 : /*
272 : * Function extended with reserved slots for use by various kinds of functions.
273 : * Most functions do not have these extensions, but enough are that efficient
274 : * storage is required (no malloc'ed reserved slots).
275 : */
276 : class FunctionExtended : public JSFunction
277 : {
278 : friend struct JSFunction;
279 :
280 : /* Reserved slots available for storage by particular native functions. */
281 : HeapValue extendedSlots[2];
282 : };
283 :
284 : } // namespace js
285 :
286 : inline js::FunctionExtended *
287 4760142 : JSFunction::toExtended()
288 : {
289 4760142 : JS_ASSERT(isExtended());
290 4760142 : return static_cast<js::FunctionExtended *>(this);
291 : }
292 :
293 : inline const js::FunctionExtended *
294 10506 : JSFunction::toExtended() const
295 : {
296 10506 : JS_ASSERT(isExtended());
297 10506 : return static_cast<const js::FunctionExtended *>(this);
298 : }
299 :
300 : extern void
301 : js_PutArgsObject(js::StackFrame *fp);
302 :
303 : inline bool
304 743853 : js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
305 :
306 : namespace js {
307 :
308 : template<XDRMode mode>
309 : bool
310 : XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
311 :
312 : } /* namespace js */
313 :
314 : extern JSBool
315 : js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
316 :
317 : extern JSBool
318 : js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
319 :
320 : extern JSObject*
321 : js_fun_bind(JSContext *cx, js::HandleObject target, js::Value thisArg,
322 : js::Value *boundArgs, unsigned argslen);
323 :
324 : #endif /* jsfun_h___ */
|