|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef jsfun_h |
|
8 #define jsfun_h |
|
9 |
|
10 /* |
|
11 * JS function definitions. |
|
12 */ |
|
13 |
|
14 #include "jsobj.h" |
|
15 #include "jsscript.h" |
|
16 #include "jstypes.h" |
|
17 |
|
18 namespace js { |
|
19 class FunctionExtended; |
|
20 |
|
21 typedef JSNative Native; |
|
22 typedef JSParallelNative ParallelNative; |
|
23 typedef JSThreadSafeNative ThreadSafeNative; |
|
24 } |
|
25 |
|
26 struct JSAtomState; |
|
27 |
|
28 class JSFunction : public JSObject |
|
29 { |
|
30 public: |
|
31 static const js::Class class_; |
|
32 |
|
33 enum Flags { |
|
34 INTERPRETED = 0x0001, /* function has a JSScript and environment. */ |
|
35 NATIVE_CTOR = 0x0002, /* native that can be called as a constructor */ |
|
36 EXTENDED = 0x0004, /* structure is FunctionExtended */ |
|
37 IS_FUN_PROTO = 0x0010, /* function is Function.prototype for some global object */ |
|
38 EXPR_CLOSURE = 0x0020, /* expression closure: function(x) x*x */ |
|
39 HAS_GUESSED_ATOM = 0x0040, /* function had no explicit name, but a |
|
40 name was guessed for it anyway */ |
|
41 LAMBDA = 0x0080, /* function comes from a FunctionExpression, ArrowFunction, or |
|
42 Function() call (not a FunctionDeclaration or nonstandard |
|
43 function-statement) */ |
|
44 SELF_HOSTED = 0x0100, /* function is self-hosted builtin and must not be |
|
45 decompilable nor constructible. */ |
|
46 SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and |
|
47 must be constructible but not decompilable. */ |
|
48 HAS_REST = 0x0400, /* function has a rest (...) parameter */ |
|
49 // 0x0800 is available |
|
50 INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */ |
|
51 ARROW = 0x2000, /* ES6 '(args) => body' syntax */ |
|
52 |
|
53 /* Derived Flags values for convenience: */ |
|
54 NATIVE_FUN = 0, |
|
55 NATIVE_LAMBDA_FUN = NATIVE_FUN | LAMBDA, |
|
56 INTERPRETED_LAMBDA = INTERPRETED | LAMBDA, |
|
57 INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW |
|
58 }; |
|
59 |
|
60 static void staticAsserts() { |
|
61 JS_STATIC_ASSERT(INTERPRETED == JS_FUNCTION_INTERPRETED_BIT); |
|
62 static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function), |
|
63 "shadow interface must match actual interface"); |
|
64 } |
|
65 |
|
66 private: |
|
67 uint16_t nargs_; /* number of formal arguments |
|
68 (including defaults and the rest parameter unlike f.length) */ |
|
69 uint16_t flags_; /* bitfield composed of the above Flags enum */ |
|
70 union U { |
|
71 class Native { |
|
72 friend class JSFunction; |
|
73 js::Native native; /* native method pointer or null */ |
|
74 const JSJitInfo *jitinfo; /* Information about this function to be |
|
75 used by the JIT; |
|
76 use the accessor! */ |
|
77 } n; |
|
78 struct Scripted { |
|
79 union { |
|
80 JSScript *script_; /* interpreted bytecode descriptor or null; |
|
81 use the accessor! */ |
|
82 js::LazyScript *lazy_; /* lazily compiled script, or nullptr */ |
|
83 } s; |
|
84 JSObject *env_; /* environment for new activations; |
|
85 use the accessor! */ |
|
86 } i; |
|
87 void *nativeOrScript; |
|
88 } u; |
|
89 js::HeapPtrAtom atom_; /* name for diagnostics and decompiling */ |
|
90 |
|
91 public: |
|
92 |
|
93 /* Call objects must be created for each invocation of a heavyweight function. */ |
|
94 bool isHeavyweight() const { |
|
95 JS_ASSERT(!isInterpretedLazy()); |
|
96 |
|
97 if (isNative()) |
|
98 return false; |
|
99 |
|
100 // Note: this should be kept in sync with FunctionBox::isHeavyweight(). |
|
101 return nonLazyScript()->hasAnyAliasedBindings() || |
|
102 nonLazyScript()->funHasExtensibleScope() || |
|
103 nonLazyScript()->funNeedsDeclEnvObject() || |
|
104 isGenerator(); |
|
105 } |
|
106 |
|
107 size_t nargs() const { |
|
108 return nargs_; |
|
109 } |
|
110 |
|
111 uint16_t flags() const { |
|
112 return flags_; |
|
113 } |
|
114 |
|
115 /* A function can be classified as either native (C++) or interpreted (JS): */ |
|
116 bool isInterpreted() const { return flags() & (INTERPRETED | INTERPRETED_LAZY); } |
|
117 bool isNative() const { return !isInterpreted(); } |
|
118 |
|
119 /* Possible attributes of a native function: */ |
|
120 bool isNativeConstructor() const { return flags() & NATIVE_CTOR; } |
|
121 |
|
122 /* Possible attributes of an interpreted function: */ |
|
123 bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; } |
|
124 bool isExprClosure() const { return flags() & EXPR_CLOSURE; } |
|
125 bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } |
|
126 bool isLambda() const { return flags() & LAMBDA; } |
|
127 bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; } |
|
128 bool isSelfHostedConstructor() const { return flags() & SELF_HOSTED_CTOR; } |
|
129 bool hasRest() const { return flags() & HAS_REST; } |
|
130 |
|
131 bool isInterpretedLazy() const { |
|
132 return flags() & INTERPRETED_LAZY; |
|
133 } |
|
134 bool hasScript() const { |
|
135 return flags() & INTERPRETED; |
|
136 } |
|
137 |
|
138 bool hasJITCode() const { |
|
139 if (!hasScript()) |
|
140 return false; |
|
141 |
|
142 return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript(); |
|
143 } |
|
144 |
|
145 // Arrow functions store their lexical |this| in the first extended slot. |
|
146 bool isArrow() const { return flags() & ARROW; } |
|
147 |
|
148 /* Compound attributes: */ |
|
149 bool isBuiltin() const { |
|
150 return isNative() || isSelfHostedBuiltin(); |
|
151 } |
|
152 bool isInterpretedConstructor() const { |
|
153 // Note: the JITs inline this check, so be careful when making changes |
|
154 // here. See IonMacroAssembler::branchIfNotInterpretedConstructor. |
|
155 return isInterpreted() && !isFunctionPrototype() && !isArrow() && |
|
156 (!isSelfHostedBuiltin() || isSelfHostedConstructor()); |
|
157 } |
|
158 bool isNamedLambda() const { |
|
159 return isLambda() && displayAtom() && !hasGuessedAtom(); |
|
160 } |
|
161 bool hasParallelNative() const { |
|
162 return isNative() && jitInfo() && jitInfo()->hasParallelNative(); |
|
163 } |
|
164 |
|
165 bool isBuiltinFunctionConstructor(); |
|
166 |
|
167 /* Returns the strictness of this function, which must be interpreted. */ |
|
168 bool strict() const { |
|
169 return nonLazyScript()->strict(); |
|
170 } |
|
171 |
|
172 void setFlags(uint16_t flags) { |
|
173 this->flags_ = flags; |
|
174 } |
|
175 |
|
176 // Can be called multiple times by the parser. |
|
177 void setArgCount(uint16_t nargs) { |
|
178 this->nargs_ = nargs; |
|
179 } |
|
180 |
|
181 // Can be called multiple times by the parser. |
|
182 void setHasRest() { |
|
183 flags_ |= HAS_REST; |
|
184 } |
|
185 |
|
186 void setIsSelfHostedBuiltin() { |
|
187 JS_ASSERT(!isSelfHostedBuiltin()); |
|
188 flags_ |= SELF_HOSTED; |
|
189 } |
|
190 |
|
191 void setIsSelfHostedConstructor() { |
|
192 JS_ASSERT(!isSelfHostedConstructor()); |
|
193 flags_ |= SELF_HOSTED_CTOR; |
|
194 } |
|
195 |
|
196 void setIsFunctionPrototype() { |
|
197 JS_ASSERT(!isFunctionPrototype()); |
|
198 flags_ |= IS_FUN_PROTO; |
|
199 } |
|
200 |
|
201 // Can be called multiple times by the parser. |
|
202 void setIsExprClosure() { |
|
203 flags_ |= EXPR_CLOSURE; |
|
204 } |
|
205 |
|
206 void setArrow() { |
|
207 flags_ |= ARROW; |
|
208 } |
|
209 |
|
210 JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } |
|
211 js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); } |
|
212 void initAtom(JSAtom *atom) { atom_.init(atom); } |
|
213 |
|
214 JSAtom *displayAtom() const { |
|
215 return atom_; |
|
216 } |
|
217 |
|
218 void setGuessedAtom(JSAtom *atom) { |
|
219 JS_ASSERT(atom_ == nullptr); |
|
220 JS_ASSERT(atom != nullptr); |
|
221 JS_ASSERT(!hasGuessedAtom()); |
|
222 atom_ = atom; |
|
223 flags_ |= HAS_GUESSED_ATOM; |
|
224 } |
|
225 |
|
226 /* uint16_t representation bounds number of call object dynamic slots. */ |
|
227 enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; |
|
228 |
|
229 /* |
|
230 * For an interpreted function, accessors for the initial scope object of |
|
231 * activations (stack frames) of the function. |
|
232 */ |
|
233 JSObject *environment() const { |
|
234 JS_ASSERT(isInterpreted()); |
|
235 return u.i.env_; |
|
236 } |
|
237 |
|
238 void setEnvironment(JSObject *obj) { |
|
239 JS_ASSERT(isInterpreted()); |
|
240 *(js::HeapPtrObject *)&u.i.env_ = obj; |
|
241 } |
|
242 |
|
243 void initEnvironment(JSObject *obj) { |
|
244 JS_ASSERT(isInterpreted()); |
|
245 ((js::HeapPtrObject *)&u.i.env_)->init(obj); |
|
246 } |
|
247 |
|
248 static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); } |
|
249 static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); } |
|
250 static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); } |
|
251 static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); } |
|
252 |
|
253 static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun); |
|
254 void relazify(JSTracer *trc); |
|
255 |
|
256 // Function Scripts |
|
257 // |
|
258 // Interpreted functions may either have an explicit JSScript (hasScript()) |
|
259 // or be lazy with sufficient information to construct the JSScript if |
|
260 // necessary (isInterpretedLazy()). |
|
261 // |
|
262 // A lazy function will have a LazyScript if the function came from parsed |
|
263 // source, or nullptr if the function is a clone of a self hosted function. |
|
264 // |
|
265 // There are several methods to get the script of an interpreted function: |
|
266 // |
|
267 // - For all interpreted functions, getOrCreateScript() will get the |
|
268 // JSScript, delazifying the function if necessary. This is the safest to |
|
269 // use, but has extra checks, requires a cx and may trigger a GC. |
|
270 // |
|
271 // - For inlined functions which may have a LazyScript but whose JSScript |
|
272 // is known to exist, existingScriptForInlinedFunction() will get the |
|
273 // script and delazify the function if necessary. |
|
274 // |
|
275 // - For functions known to have a JSScript, nonLazyScript() will get it. |
|
276 |
|
277 JSScript *getOrCreateScript(JSContext *cx) { |
|
278 JS_ASSERT(isInterpreted()); |
|
279 JS_ASSERT(cx); |
|
280 if (isInterpretedLazy()) { |
|
281 JS::RootedFunction self(cx, this); |
|
282 if (!createScriptForLazilyInterpretedFunction(cx, self)) |
|
283 return nullptr; |
|
284 return self->nonLazyScript(); |
|
285 } |
|
286 return nonLazyScript(); |
|
287 } |
|
288 |
|
289 JSScript *existingScriptForInlinedFunction() { |
|
290 MOZ_ASSERT(isInterpreted()); |
|
291 if (isInterpretedLazy()) { |
|
292 // Get the script from the canonical function. Ion used the |
|
293 // canonical function to inline the script and because it has |
|
294 // Baseline code it has not been relazified. Note that we can't |
|
295 // use lazyScript->script_ here as it may be null in some cases, |
|
296 // see bug 976536. |
|
297 js::LazyScript *lazy = lazyScript(); |
|
298 JSFunction *fun = lazy->functionNonDelazifying(); |
|
299 MOZ_ASSERT(fun); |
|
300 JSScript *script = fun->nonLazyScript(); |
|
301 |
|
302 if (shadowZone()->needsBarrier()) |
|
303 js::LazyScript::writeBarrierPre(lazy); |
|
304 |
|
305 flags_ &= ~INTERPRETED_LAZY; |
|
306 flags_ |= INTERPRETED; |
|
307 initScript(script); |
|
308 } |
|
309 return nonLazyScript(); |
|
310 } |
|
311 |
|
312 JSScript *nonLazyScript() const { |
|
313 JS_ASSERT(hasScript()); |
|
314 JS_ASSERT(u.i.s.script_); |
|
315 return u.i.s.script_; |
|
316 } |
|
317 |
|
318 // Returns non-callsited-clone version of this. Use when return |
|
319 // value can flow to arbitrary JS (see Bug 944975). |
|
320 JSFunction* originalFunction() { |
|
321 if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) { |
|
322 return this->nonLazyScript()->donorFunction(); |
|
323 } else { |
|
324 return this; |
|
325 } |
|
326 } |
|
327 |
|
328 js::HeapPtrScript &mutableScript() { |
|
329 JS_ASSERT(isInterpreted()); |
|
330 return *(js::HeapPtrScript *)&u.i.s.script_; |
|
331 } |
|
332 |
|
333 js::LazyScript *lazyScript() const { |
|
334 JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_); |
|
335 return u.i.s.lazy_; |
|
336 } |
|
337 |
|
338 js::LazyScript *lazyScriptOrNull() const { |
|
339 JS_ASSERT(isInterpretedLazy()); |
|
340 return u.i.s.lazy_; |
|
341 } |
|
342 |
|
343 js::GeneratorKind generatorKind() const { |
|
344 if (!isInterpreted()) |
|
345 return js::NotGenerator; |
|
346 if (hasScript()) |
|
347 return nonLazyScript()->generatorKind(); |
|
348 if (js::LazyScript *lazy = lazyScriptOrNull()) |
|
349 return lazy->generatorKind(); |
|
350 JS_ASSERT(isSelfHostedBuiltin()); |
|
351 return js::NotGenerator; |
|
352 } |
|
353 |
|
354 bool isGenerator() const { return generatorKind() != js::NotGenerator; } |
|
355 |
|
356 bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; } |
|
357 |
|
358 bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } |
|
359 |
|
360 void setScript(JSScript *script_) { |
|
361 JS_ASSERT(hasScript()); |
|
362 mutableScript() = script_; |
|
363 } |
|
364 |
|
365 void initScript(JSScript *script_) { |
|
366 JS_ASSERT(hasScript()); |
|
367 mutableScript().init(script_); |
|
368 } |
|
369 |
|
370 void setUnlazifiedScript(JSScript *script) { |
|
371 // Note: createScriptForLazilyInterpretedFunction triggers a barrier on |
|
372 // lazy script before it is overwritten here. |
|
373 JS_ASSERT(isInterpretedLazy()); |
|
374 if (!lazyScript()->maybeScript()) |
|
375 lazyScript()->initScript(script); |
|
376 flags_ &= ~INTERPRETED_LAZY; |
|
377 flags_ |= INTERPRETED; |
|
378 initScript(script); |
|
379 } |
|
380 |
|
381 void initLazyScript(js::LazyScript *lazy) { |
|
382 JS_ASSERT(isInterpreted()); |
|
383 flags_ &= ~INTERPRETED; |
|
384 flags_ |= INTERPRETED_LAZY; |
|
385 u.i.s.lazy_ = lazy; |
|
386 } |
|
387 |
|
388 JSNative native() const { |
|
389 JS_ASSERT(isNative()); |
|
390 return u.n.native; |
|
391 } |
|
392 |
|
393 JSNative maybeNative() const { |
|
394 return isInterpreted() ? nullptr : native(); |
|
395 } |
|
396 |
|
397 JSParallelNative parallelNative() const { |
|
398 JS_ASSERT(hasParallelNative()); |
|
399 return jitInfo()->parallelNative; |
|
400 } |
|
401 |
|
402 JSParallelNative maybeParallelNative() const { |
|
403 return hasParallelNative() ? parallelNative() : nullptr; |
|
404 } |
|
405 |
|
406 void initNative(js::Native native, const JSJitInfo *jitinfo) { |
|
407 JS_ASSERT(native); |
|
408 u.n.native = native; |
|
409 u.n.jitinfo = jitinfo; |
|
410 } |
|
411 |
|
412 const JSJitInfo *jitInfo() const { |
|
413 JS_ASSERT(isNative()); |
|
414 return u.n.jitinfo; |
|
415 } |
|
416 |
|
417 void setJitInfo(const JSJitInfo *data) { |
|
418 JS_ASSERT(isNative()); |
|
419 u.n.jitinfo = data; |
|
420 } |
|
421 |
|
422 static unsigned offsetOfNativeOrScript() { |
|
423 JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.s.script_)); |
|
424 JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript)); |
|
425 return offsetof(JSFunction, u.nativeOrScript); |
|
426 } |
|
427 |
|
428 #if JS_BITS_PER_WORD == 32 |
|
429 static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2_BACKGROUND; |
|
430 static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND; |
|
431 #else |
|
432 static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND; |
|
433 static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND; |
|
434 #endif |
|
435 |
|
436 inline void trace(JSTracer *trc); |
|
437 |
|
438 /* Bound function accessors. */ |
|
439 |
|
440 inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg, |
|
441 const js::Value *args, unsigned argslen); |
|
442 |
|
443 JSObject *getBoundFunctionTarget() const { |
|
444 JS_ASSERT(isBoundFunction()); |
|
445 |
|
446 /* Bound functions abuse |parent| to store their target function. */ |
|
447 return getParent(); |
|
448 } |
|
449 |
|
450 const js::Value &getBoundFunctionThis() const; |
|
451 const js::Value &getBoundFunctionArgument(unsigned which) const; |
|
452 size_t getBoundFunctionArgumentCount() const; |
|
453 |
|
454 private: |
|
455 inline js::FunctionExtended *toExtended(); |
|
456 inline const js::FunctionExtended *toExtended() const; |
|
457 |
|
458 public: |
|
459 inline bool isExtended() const { |
|
460 JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind); |
|
461 JS_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (tenuredGetAllocKind() == ExtendedFinalizeKind)); |
|
462 return !!(flags() & EXTENDED); |
|
463 } |
|
464 |
|
465 /* |
|
466 * Accessors for data stored in extended functions. Use setExtendedSlot if |
|
467 * the function has already been initialized. Otherwise use |
|
468 * initExtendedSlot. |
|
469 */ |
|
470 inline void initializeExtended(); |
|
471 inline void initExtendedSlot(size_t which, const js::Value &val); |
|
472 inline void setExtendedSlot(size_t which, const js::Value &val); |
|
473 inline const js::Value &getExtendedSlot(size_t which) const; |
|
474 |
|
475 /* Constructs a new type for the function if necessary. */ |
|
476 static bool setTypeForScriptedFunction(js::ExclusiveContext *cx, js::HandleFunction fun, |
|
477 bool singleton = false); |
|
478 |
|
479 /* GC support. */ |
|
480 js::gc::AllocKind getAllocKind() const { |
|
481 js::gc::AllocKind kind = FinalizeKind; |
|
482 if (isExtended()) |
|
483 kind = ExtendedFinalizeKind; |
|
484 JS_ASSERT_IF(isTenured(), kind == tenuredGetAllocKind()); |
|
485 return kind; |
|
486 } |
|
487 }; |
|
488 |
|
489 extern JSString * |
|
490 fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent); |
|
491 |
|
492 inline JSFunction::Flags |
|
493 JSAPIToJSFunctionFlags(unsigned flags) |
|
494 { |
|
495 return (flags & JSFUN_CONSTRUCTOR) |
|
496 ? JSFunction::NATIVE_CTOR |
|
497 : JSFunction::NATIVE_FUN; |
|
498 } |
|
499 |
|
500 namespace js { |
|
501 |
|
502 extern bool |
|
503 Function(JSContext *cx, unsigned argc, Value *vp); |
|
504 |
|
505 extern bool |
|
506 Generator(JSContext *cx, unsigned argc, Value *vp); |
|
507 |
|
508 extern JSFunction * |
|
509 NewFunction(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs, |
|
510 JSFunction::Flags flags, HandleObject parent, HandleAtom atom, |
|
511 gc::AllocKind allocKind = JSFunction::FinalizeKind, |
|
512 NewObjectKind newKind = GenericObject); |
|
513 |
|
514 // If proto is nullptr, Function.prototype is used instead. |
|
515 extern JSFunction * |
|
516 NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs, |
|
517 JSFunction::Flags flags, HandleObject parent, HandleAtom atom, |
|
518 JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind, |
|
519 NewObjectKind newKind = GenericObject); |
|
520 |
|
521 extern JSFunction * |
|
522 DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native, |
|
523 unsigned nargs, unsigned flags, |
|
524 gc::AllocKind allocKind = JSFunction::FinalizeKind, |
|
525 NewObjectKind newKind = GenericObject); |
|
526 |
|
527 bool |
|
528 FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name); |
|
529 |
|
530 extern bool |
|
531 fun_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp); |
|
532 |
|
533 // ES6 9.2.5 IsConstructor |
|
534 bool IsConstructor(const Value &v); |
|
535 |
|
536 /* |
|
537 * Function extended with reserved slots for use by various kinds of functions. |
|
538 * Most functions do not have these extensions, but enough do that efficient |
|
539 * storage is required (no malloc'ed reserved slots). |
|
540 */ |
|
541 class FunctionExtended : public JSFunction |
|
542 { |
|
543 public: |
|
544 static const unsigned NUM_EXTENDED_SLOTS = 2; |
|
545 |
|
546 /* Arrow functions store their lexical |this| in the first extended slot. */ |
|
547 static const unsigned ARROW_THIS_SLOT = 0; |
|
548 |
|
549 static inline size_t offsetOfExtendedSlot(unsigned which) { |
|
550 MOZ_ASSERT(which < NUM_EXTENDED_SLOTS); |
|
551 return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue); |
|
552 } |
|
553 static inline size_t offsetOfArrowThisSlot() { |
|
554 return offsetOfExtendedSlot(ARROW_THIS_SLOT); |
|
555 } |
|
556 |
|
557 private: |
|
558 friend class JSFunction; |
|
559 |
|
560 /* Reserved slots available for storage by particular native functions. */ |
|
561 HeapValue extendedSlots[NUM_EXTENDED_SLOTS]; |
|
562 }; |
|
563 |
|
564 extern JSFunction * |
|
565 CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, |
|
566 gc::AllocKind kind = JSFunction::FinalizeKind, |
|
567 NewObjectKind newKindArg = GenericObject); |
|
568 |
|
569 |
|
570 extern bool |
|
571 FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length, |
|
572 size_t *bodyStart, size_t *bodyEnd); |
|
573 |
|
574 } // namespace js |
|
575 |
|
576 inline js::FunctionExtended * |
|
577 JSFunction::toExtended() |
|
578 { |
|
579 JS_ASSERT(isExtended()); |
|
580 return static_cast<js::FunctionExtended *>(this); |
|
581 } |
|
582 |
|
583 inline const js::FunctionExtended * |
|
584 JSFunction::toExtended() const |
|
585 { |
|
586 JS_ASSERT(isExtended()); |
|
587 return static_cast<const js::FunctionExtended *>(this); |
|
588 } |
|
589 |
|
590 inline void |
|
591 JSFunction::initializeExtended() |
|
592 { |
|
593 JS_ASSERT(isExtended()); |
|
594 |
|
595 JS_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2); |
|
596 toExtended()->extendedSlots[0].init(js::UndefinedValue()); |
|
597 toExtended()->extendedSlots[1].init(js::UndefinedValue()); |
|
598 } |
|
599 |
|
600 inline void |
|
601 JSFunction::initExtendedSlot(size_t which, const js::Value &val) |
|
602 { |
|
603 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
|
604 toExtended()->extendedSlots[which].init(val); |
|
605 } |
|
606 |
|
607 inline void |
|
608 JSFunction::setExtendedSlot(size_t which, const js::Value &val) |
|
609 { |
|
610 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
|
611 toExtended()->extendedSlots[which] = val; |
|
612 } |
|
613 |
|
614 inline const js::Value & |
|
615 JSFunction::getExtendedSlot(size_t which) const |
|
616 { |
|
617 JS_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); |
|
618 return toExtended()->extendedSlots[which]; |
|
619 } |
|
620 |
|
621 namespace js { |
|
622 |
|
623 JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen); |
|
624 |
|
625 template<XDRMode mode> |
|
626 bool |
|
627 XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, |
|
628 HandleScript enclosingScript, MutableHandleObject objp); |
|
629 |
|
630 extern JSObject * |
|
631 CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun); |
|
632 |
|
633 /* |
|
634 * Report an error that call.thisv is not compatible with the specified class, |
|
635 * assuming that the method (clasp->name).prototype.<name of callee function> |
|
636 * is what was called. |
|
637 */ |
|
638 extern void |
|
639 ReportIncompatibleMethod(JSContext *cx, CallReceiver call, const Class *clasp); |
|
640 |
|
641 /* |
|
642 * Report an error that call.thisv is not an acceptable this for the callee |
|
643 * function. |
|
644 */ |
|
645 extern void |
|
646 ReportIncompatible(JSContext *cx, CallReceiver call); |
|
647 |
|
648 bool |
|
649 CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *); |
|
650 |
|
651 extern const JSFunctionSpec function_methods[]; |
|
652 |
|
653 } /* namespace js */ |
|
654 |
|
655 extern bool |
|
656 js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp); |
|
657 |
|
658 extern bool |
|
659 js_fun_call(JSContext *cx, unsigned argc, js::Value *vp); |
|
660 |
|
661 extern JSObject* |
|
662 js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg, |
|
663 js::Value *boundArgs, unsigned argslen); |
|
664 |
|
665 #ifdef DEBUG |
|
666 namespace JS { |
|
667 namespace detail { |
|
668 |
|
669 JS_PUBLIC_API(void) |
|
670 CheckIsValidConstructible(Value calleev); |
|
671 |
|
672 } // namespace detail |
|
673 } // namespace JS |
|
674 #endif |
|
675 |
|
676 #endif /* jsfun_h */ |