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 
20 namespace frontend {
21 class FunctionBox;
22 }
23 
24 class FunctionExtended;
25 
26 typedef JSNative           Native;
27 } // namespace js
28 
29 struct JSAtomState;
30 
31 class JSFunction : public js::NativeObject
32 {
33   public:
34     static const js::Class class_;
35 
36     enum FunctionKind {
37         NormalFunction = 0,
38         Arrow,                      /* ES6 '(args) => body' syntax */
39         Method,                     /* ES6 MethodDefinition */
40         ClassConstructor,
41         Getter,
42         Setter,
43         AsmJS,                      /* function is an asm.js module or exported function */
44         FunctionKindLimit
45     };
46 
47     enum Flags {
48         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
49         CONSTRUCTOR      = 0x0002,  /* function that can be called as a constructor */
50         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
51         IS_FUN_PROTO     = 0x0008,  /* function is Function.prototype for some global object */
52         EXPR_BODY        = 0x0010,  /* arrow function with expression body or
53                                      * expression closure: function(x) x*x */
54         HAS_GUESSED_ATOM = 0x0020,  /* function had no explicit name, but a
55                                        name was guessed for it anyway */
56         LAMBDA           = 0x0040,  /* function comes from a FunctionExpression, ArrowFunction, or
57                                        Function() call (not a FunctionDeclaration or nonstandard
58                                        function-statement) */
59         SELF_HOSTED      = 0x0080,  /* function is self-hosted builtin and must not be
60                                        decompilable nor constructible. */
61         HAS_REST         = 0x0100,  /* function has a rest (...) parameter */
62         INTERPRETED_LAZY = 0x0200,  /* function is interpreted but doesn't have a script yet */
63         RESOLVED_LENGTH  = 0x0400,  /* f.length has been resolved (see fun_resolve). */
64         RESOLVED_NAME    = 0x0800,  /* f.name has been resolved (see fun_resolve). */
65         BEING_PARSED     = 0x1000,  /* function is currently being parsed; has
66                                        a funbox in place of an environment */
67 
68         FUNCTION_KIND_SHIFT = 13,
69         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
70 
71         ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
72         ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
73         METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
74         CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
75         GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
76         SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
77 
78         /* Derived Flags values for convenience: */
79         NATIVE_FUN = 0,
80         NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
81         NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
82         ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
83         ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
84         INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
85         INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
86         INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
87         INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
88         INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
89         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
90         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
91         INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
92         INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
93         INTERPRETED_GENERATOR = INTERPRETED,
94         NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
95 
96         STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM |
97                                LAMBDA | SELF_HOSTED |  HAS_REST | FUNCTION_KIND_MASK
98     };
99 
100     static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
101                   "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
102     static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
103                   "FunctionKind doesn't fit into flags_");
104 
105     // Implemented in Parser.cpp. Used so the static scope chain may be walked
106     // in Parser without a JSScript.
107     class MOZ_STACK_CLASS AutoParseUsingFunctionBox
108     {
109         js::RootedFunction fun_;
110         js::RootedObject oldEnv_;
111 
112       public:
113         AutoParseUsingFunctionBox(js::ExclusiveContext* cx, js::frontend::FunctionBox* funbox);
114         ~AutoParseUsingFunctionBox();
115     };
116 
117   private:
118     uint16_t        nargs_;       /* number of formal arguments
119                                      (including defaults and the rest parameter unlike f.length) */
120     uint16_t        flags_;       /* bitfield composed of the above Flags enum, as well as the kind */
121     union U {
122         class Native {
123             friend class JSFunction;
124             js::Native          native;       /* native method pointer or null */
125             const JSJitInfo*    jitinfo;     /* Information about this function to be
126                                                  used by the JIT;
127                                                  use the accessor! */
128         } n;
129         struct Scripted {
130             union {
131                 JSScript* script_; /* interpreted bytecode descriptor or null;
132                                       use the accessor! */
133                 js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
134             } s;
135             union {
136                 JSObject*   env_;    /* environment for new activations;
137                                         use the accessor! */
138                 js::frontend::FunctionBox* funbox_; /* the function box when parsing */
139             };
140         } i;
141         void*           nativeOrScript;
142     } u;
143     js::HeapPtrAtom  atom_;       /* name for diagnostics and decompiling */
144 
145   public:
146 
147     /* Call objects must be created for each invocation of this function. */
needsCallObject()148     bool needsCallObject() const {
149         MOZ_ASSERT(!isInterpretedLazy());
150         MOZ_ASSERT(!isBeingParsed());
151 
152         if (isNative())
153             return false;
154 
155         // Note: this should be kept in sync with FunctionBox::needsCallObject().
156         return nonLazyScript()->hasAnyAliasedBindings() ||
157                nonLazyScript()->funHasExtensibleScope() ||
158                nonLazyScript()->funNeedsDeclEnvObject() ||
159                nonLazyScript()->needsHomeObject()       ||
160                nonLazyScript()->isDerivedClassConstructor() ||
161                isGenerator();
162     }
163 
nargs()164     size_t nargs() const {
165         return nargs_;
166     }
167 
flags()168     uint16_t flags() const {
169         return flags_;
170     }
171 
kind()172     FunctionKind kind() const {
173         return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT);
174     }
175 
176     /* A function can be classified as either native (C++) or interpreted (JS): */
isInterpreted()177     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
isNative()178     bool isNative()                 const { return !isInterpreted(); }
179 
isConstructor()180     bool isConstructor()            const { return flags() & CONSTRUCTOR; }
181 
182     /* Possible attributes of a native function: */
isAsmJSNative()183     bool isAsmJSNative()            const { return kind() == AsmJS; }
184 
185     /* Possible attributes of an interpreted function: */
isFunctionPrototype()186     bool isFunctionPrototype()      const { return flags() & IS_FUN_PROTO; }
isExprBody()187     bool isExprBody()               const { return flags() & EXPR_BODY; }
hasGuessedAtom()188     bool hasGuessedAtom()           const { return flags() & HAS_GUESSED_ATOM; }
isLambda()189     bool isLambda()                 const { return flags() & LAMBDA; }
isSelfHostedBuiltin()190     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
hasRest()191     bool hasRest()                  const { return flags() & HAS_REST; }
isInterpretedLazy()192     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
hasScript()193     bool hasScript()                const { return flags() & INTERPRETED; }
isBeingParsed()194     bool isBeingParsed()            const { return flags() & BEING_PARSED; }
195 
196     // Arrow functions store their lexical new.target in the first extended slot.
isArrow()197     bool isArrow()                  const { return kind() == Arrow; }
198     // Every class-constructor is also a method.
isMethod()199     bool isMethod()                 const { return kind() == Method || kind() == ClassConstructor; }
isClassConstructor()200     bool isClassConstructor()       const { return kind() == ClassConstructor; }
201 
isGetter()202     bool isGetter()                 const { return kind() == Getter; }
isSetter()203     bool isSetter()                 const { return kind() == Setter; }
204 
allowSuperProperty()205     bool allowSuperProperty() const {
206         return isMethod() || isGetter() || isSetter();
207     }
208 
hasResolvedLength()209     bool hasResolvedLength()        const { return flags() & RESOLVED_LENGTH; }
hasResolvedName()210     bool hasResolvedName()          const { return flags() & RESOLVED_NAME; }
211 
hasJITCode()212     bool hasJITCode() const {
213         if (!hasScript())
214             return false;
215 
216         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
217     }
218 
219     /* Compound attributes: */
isBuiltin()220     bool isBuiltin() const {
221         return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
222     }
223 
isNamedLambda()224     bool isNamedLambda() const {
225         return isLambda() && displayAtom() && !hasGuessedAtom();
226     }
227 
hasLexicalThis()228     bool hasLexicalThis() const {
229         return isArrow() || nonLazyScript()->isGeneratorExp();
230     }
231 
232     bool isBuiltinFunctionConstructor();
233 
234     /* Returns the strictness of this function, which must be interpreted. */
strict()235     bool strict() const {
236         MOZ_ASSERT(isInterpreted());
237         return isInterpretedLazy() ? lazyScript()->strict() : nonLazyScript()->strict();
238     }
239 
setFlags(uint16_t flags)240     void setFlags(uint16_t flags) {
241         this->flags_ = flags;
242     }
setKind(FunctionKind kind)243     void setKind(FunctionKind kind) {
244         this->flags_ &= ~FUNCTION_KIND_MASK;
245         this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
246     }
247 
248     // Make the function constructible.
setIsConstructor()249     void setIsConstructor() {
250         MOZ_ASSERT(!isConstructor());
251         MOZ_ASSERT(isSelfHostedBuiltin());
252         flags_ |= CONSTRUCTOR;
253     }
254 
255     // Can be called multiple times by the parser.
setArgCount(uint16_t nargs)256     void setArgCount(uint16_t nargs) {
257         this->nargs_ = nargs;
258     }
259 
260     // Can be called multiple times by the parser.
setHasRest()261     void setHasRest() {
262         flags_ |= HAS_REST;
263     }
264 
setIsSelfHostedBuiltin()265     void setIsSelfHostedBuiltin() {
266         MOZ_ASSERT(!isSelfHostedBuiltin());
267         flags_ |= SELF_HOSTED;
268         // Self-hosted functions should not be constructable.
269         flags_ &= ~CONSTRUCTOR;
270     }
271 
setIsFunctionPrototype()272     void setIsFunctionPrototype() {
273         MOZ_ASSERT(!isFunctionPrototype());
274         flags_ |= IS_FUN_PROTO;
275     }
276 
277     // Can be called multiple times by the parser.
setIsExprBody()278     void setIsExprBody() {
279         flags_ |= EXPR_BODY;
280     }
281 
setArrow()282     void setArrow() {
283         setKind(Arrow);
284     }
285 
setResolvedLength()286     void setResolvedLength() {
287         flags_ |= RESOLVED_LENGTH;
288     }
289 
setResolvedName()290     void setResolvedName() {
291         flags_ |= RESOLVED_NAME;
292     }
293 
atom()294     JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
295 
name()296     js::PropertyName* name() const {
297         return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName();
298     }
299 
initAtom(JSAtom * atom)300     void initAtom(JSAtom* atom) { atom_.init(atom); }
301 
displayAtom()302     JSAtom* displayAtom() const {
303         return atom_;
304     }
305 
setGuessedAtom(JSAtom * atom)306     void setGuessedAtom(JSAtom* atom) {
307         MOZ_ASSERT(!atom_);
308         MOZ_ASSERT(atom);
309         MOZ_ASSERT(!hasGuessedAtom());
310         atom_ = atom;
311         flags_ |= HAS_GUESSED_ATOM;
312     }
313 
314     /* uint16_t representation bounds number of call object dynamic slots. */
315     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
316 
317     /*
318      * For an interpreted function, accessors for the initial scope object of
319      * activations (stack frames) of the function.
320      */
environment()321     JSObject* environment() const {
322         MOZ_ASSERT(isInterpreted() && !isBeingParsed());
323         return u.i.env_;
324     }
325 
setEnvironment(JSObject * obj)326     void setEnvironment(JSObject* obj) {
327         MOZ_ASSERT(isInterpreted() && !isBeingParsed());
328         *reinterpret_cast<js::HeapPtrObject*>(&u.i.env_) = obj;
329     }
330 
initEnvironment(JSObject * obj)331     void initEnvironment(JSObject* obj) {
332         MOZ_ASSERT(isInterpreted() && !isBeingParsed());
333         reinterpret_cast<js::HeapPtrObject*>(&u.i.env_)->init(obj);
334     }
335 
unsetEnvironment()336     void unsetEnvironment() {
337         setEnvironment(nullptr);
338     }
339 
340   private:
setFunctionBox(js::frontend::FunctionBox * funbox)341     void setFunctionBox(js::frontend::FunctionBox* funbox) {
342         MOZ_ASSERT(isInterpreted());
343         MOZ_ASSERT_IF(!isBeingParsed(), !environment());
344         flags_ |= BEING_PARSED;
345         u.i.funbox_ = funbox;
346     }
347 
unsetFunctionBox()348     void unsetFunctionBox() {
349         MOZ_ASSERT(isBeingParsed());
350         flags_ &= ~BEING_PARSED;
351         u.i.funbox_ = nullptr;
352     }
353 
354   public:
offsetOfNargs()355     static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
offsetOfFlags()356     static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
offsetOfEnvironment()357     static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
offsetOfAtom()358     static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
359 
360     static bool createScriptForLazilyInterpretedFunction(JSContext* cx, js::HandleFunction fun);
361     void maybeRelazify(JSRuntime* rt);
362 
363     // Function Scripts
364     //
365     // Interpreted functions may either have an explicit JSScript (hasScript())
366     // or be lazy with sufficient information to construct the JSScript if
367     // necessary (isInterpretedLazy()).
368     //
369     // A lazy function will have a LazyScript if the function came from parsed
370     // source, or nullptr if the function is a clone of a self hosted function.
371     //
372     // There are several methods to get the script of an interpreted function:
373     //
374     // - For all interpreted functions, getOrCreateScript() will get the
375     //   JSScript, delazifying the function if necessary. This is the safest to
376     //   use, but has extra checks, requires a cx and may trigger a GC.
377     //
378     // - For inlined functions which may have a LazyScript but whose JSScript
379     //   is known to exist, existingScriptForInlinedFunction() will get the
380     //   script and delazify the function if necessary.
381     //
382     // - For functions known to have a JSScript, nonLazyScript() will get it.
383 
getOrCreateScript(JSContext * cx)384     JSScript* getOrCreateScript(JSContext* cx) {
385         MOZ_ASSERT(isInterpreted());
386         MOZ_ASSERT(cx);
387         if (isInterpretedLazy()) {
388             JS::RootedFunction self(cx, this);
389             if (!createScriptForLazilyInterpretedFunction(cx, self))
390                 return nullptr;
391             return self->nonLazyScript();
392         }
393         return nonLazyScript();
394     }
395 
existingScriptForInlinedFunction()396     JSScript* existingScriptForInlinedFunction() {
397         MOZ_ASSERT(isInterpreted());
398         if (isInterpretedLazy()) {
399             // Get the script from the canonical function. Ion used the
400             // canonical function to inline the script and because it has
401             // Baseline code it has not been relazified. Note that we can't
402             // use lazyScript->script_ here as it may be null in some cases,
403             // see bug 976536.
404             js::LazyScript* lazy = lazyScript();
405             JSFunction* fun = lazy->functionNonDelazifying();
406             MOZ_ASSERT(fun);
407             JSScript* script = fun->nonLazyScript();
408 
409             if (shadowZone()->needsIncrementalBarrier())
410                 js::LazyScript::writeBarrierPre(lazy);
411 
412             flags_ &= ~INTERPRETED_LAZY;
413             flags_ |= INTERPRETED;
414             initScript(script);
415         }
416         return nonLazyScript();
417     }
418 
419     // The state of a JSFunction whose script errored out during bytecode
420     // compilation. Such JSFunctions are only reachable via GC iteration and
421     // not from script.
hasUncompiledScript()422     bool hasUncompiledScript() const {
423         MOZ_ASSERT(hasScript());
424         return !u.i.s.script_;
425     }
426 
nonLazyScript()427     JSScript* nonLazyScript() const {
428         MOZ_ASSERT(!hasUncompiledScript());
429         return u.i.s.script_;
430     }
431 
getLength(JSContext * cx,uint16_t * length)432     bool getLength(JSContext* cx, uint16_t* length) {
433         JS::RootedFunction self(cx, this);
434         if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
435             return false;
436 
437         *length = self->hasScript() ? self->nonLazyScript()->funLength()
438                                     : (self->nargs() - self->hasRest());
439         return true;
440     }
441 
lazyScript()442     js::LazyScript* lazyScript() const {
443         MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
444         return u.i.s.lazy_;
445     }
446 
lazyScriptOrNull()447     js::LazyScript* lazyScriptOrNull() const {
448         MOZ_ASSERT(isInterpretedLazy());
449         return u.i.s.lazy_;
450     }
451 
functionBox()452     js::frontend::FunctionBox* functionBox() const {
453         MOZ_ASSERT(isBeingParsed());
454         return u.i.funbox_;
455     }
456 
generatorKind()457     js::GeneratorKind generatorKind() const {
458         if (!isInterpreted())
459             return js::NotGenerator;
460         if (hasScript())
461             return nonLazyScript()->generatorKind();
462         if (js::LazyScript* lazy = lazyScriptOrNull())
463             return lazy->generatorKind();
464         MOZ_ASSERT(isSelfHostedBuiltin());
465         return js::NotGenerator;
466     }
467 
isGenerator()468     bool isGenerator() const { return generatorKind() != js::NotGenerator; }
469 
isLegacyGenerator()470     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
471 
isStarGenerator()472     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
473 
setScript(JSScript * script_)474     void setScript(JSScript* script_) {
475         mutableScript() = script_;
476     }
477 
initScript(JSScript * script_)478     void initScript(JSScript* script_) {
479         mutableScript().init(script_);
480     }
481 
setUnlazifiedScript(JSScript * script)482     void setUnlazifiedScript(JSScript* script) {
483         // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
484         // lazy script before it is overwritten here.
485         MOZ_ASSERT(isInterpretedLazy());
486         if (lazyScriptOrNull() && !lazyScript()->maybeScript())
487             lazyScript()->initScript(script);
488         flags_ &= ~INTERPRETED_LAZY;
489         flags_ |= INTERPRETED;
490         initScript(script);
491     }
492 
initLazyScript(js::LazyScript * lazy)493     void initLazyScript(js::LazyScript* lazy) {
494         MOZ_ASSERT(isInterpreted());
495         flags_ &= ~INTERPRETED;
496         flags_ |= INTERPRETED_LAZY;
497         u.i.s.lazy_ = lazy;
498     }
499 
native()500     JSNative native() const {
501         MOZ_ASSERT(isNative());
502         return u.n.native;
503     }
504 
maybeNative()505     JSNative maybeNative() const {
506         return isInterpreted() ? nullptr : native();
507     }
508 
initNative(js::Native native,const JSJitInfo * jitinfo)509     void initNative(js::Native native, const JSJitInfo* jitinfo) {
510         MOZ_ASSERT(native);
511         u.n.native = native;
512         u.n.jitinfo = jitinfo;
513     }
514 
jitInfo()515     const JSJitInfo* jitInfo() const {
516         MOZ_ASSERT(isNative());
517         return u.n.jitinfo;
518     }
519 
setJitInfo(const JSJitInfo * data)520     void setJitInfo(const JSJitInfo* data) {
521         MOZ_ASSERT(isNative());
522         u.n.jitinfo = data;
523     }
524 
isDerivedClassConstructor()525     bool isDerivedClassConstructor() {
526         bool derived;
527         if (isInterpretedLazy())
528             derived = !isSelfHostedBuiltin() && lazyScript()->isDerivedClassConstructor();
529         else
530             derived = nonLazyScript()->isDerivedClassConstructor();
531         MOZ_ASSERT_IF(derived, isClassConstructor());
532         return derived;
533     }
534 
offsetOfNativeOrScript()535     static unsigned offsetOfNativeOrScript() {
536         static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
537                       "native and script pointers must be in the same spot "
538                       "for offsetOfNativeOrScript() have any sense");
539         static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
540                       "U::nativeOrScript must be at the same offset as "
541                       "native");
542 
543         return offsetof(JSFunction, u.nativeOrScript);
544     }
545 
546     inline void trace(JSTracer* trc);
547 
548     /* Bound function accessors. */
549 
550     inline bool initBoundFunction(JSContext* cx, js::HandleObject target, js::HandleValue thisArg,
551                                   const js::Value* args, unsigned argslen);
552 
553     JSObject* getBoundFunctionTarget() const;
554     const js::Value& getBoundFunctionThis() const;
555     const js::Value& getBoundFunctionArgument(unsigned which) const;
556     size_t getBoundFunctionArgumentCount() const;
557 
558   private:
mutableScript()559     js::HeapPtrScript& mutableScript() {
560         MOZ_ASSERT(hasScript());
561         return *(js::HeapPtrScript*)&u.i.s.script_;
562     }
563 
564     inline js::FunctionExtended* toExtended();
565     inline const js::FunctionExtended* toExtended() const;
566 
567   public:
isExtended()568     inline bool isExtended() const {
569         bool extended = !!(flags() & EXTENDED);
570         MOZ_ASSERT_IF(isTenured(),
571                       extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED));
572         return extended;
573     }
574 
575     /*
576      * Accessors for data stored in extended functions. Use setExtendedSlot if
577      * the function has already been initialized. Otherwise use
578      * initExtendedSlot.
579      */
580     inline void initializeExtended();
581     inline void initExtendedSlot(size_t which, const js::Value& val);
582     inline void setExtendedSlot(size_t which, const js::Value& val);
583     inline const js::Value& getExtendedSlot(size_t which) const;
584 
585     /* Constructs a new type for the function if necessary. */
586     static bool setTypeForScriptedFunction(js::ExclusiveContext* cx, js::HandleFunction fun,
587                                            bool singleton = false);
588 
589     /* GC support. */
getAllocKind()590     js::gc::AllocKind getAllocKind() const {
591         static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
592                       "extended/non-extended AllocKinds have to be different "
593                       "for getAllocKind() to have a reason to exist");
594 
595         js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
596         if (isExtended())
597             kind = js::gc::AllocKind::FUNCTION_EXTENDED;
598         MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
599         return kind;
600     }
601 };
602 
603 static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
604               "shadow interface must match actual interface");
605 
606 extern JSString*
607 fun_toStringHelper(JSContext* cx, js::HandleObject obj, unsigned indent);
608 
609 namespace js {
610 
611 extern bool
612 Function(JSContext* cx, unsigned argc, Value* vp);
613 
614 extern bool
615 Generator(JSContext* cx, unsigned argc, Value* vp);
616 
617 // Allocate a new function backed by a JSNative.
618 extern JSFunction*
619 NewNativeFunction(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
620                   gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
621                   NewObjectKind newKind = GenericObject);
622 
623 // Allocate a new constructor backed by a JSNative.
624 extern JSFunction*
625 NewNativeConstructor(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
626                      gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
627                      NewObjectKind newKind = GenericObject,
628                      JSFunction::Flags flags = JSFunction::NATIVE_CTOR);
629 
630 // Allocate a new scripted function.  If enclosingDynamicScope is null, the
631 // global will be used.  In all cases the parent of the resulting object will be
632 // the global.
633 extern JSFunction*
634 NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
635                     HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
636                     NewObjectKind newKind = GenericObject,
637                     HandleObject enclosingDynamicScope = nullptr);
638 
639 // By default, if proto is nullptr, Function.prototype is used instead.i
640 // If protoHandling is NewFunctionExactProto, and proto is nullptr, the created
641 // function will use nullptr as its [[Prototype]] instead. If
642 // enclosingDynamicScope is null, the function will have a null environment()
643 // (yes, null, not the global).  In all cases, the global will be used as the
644 // parent.
645 
646 enum NewFunctionProtoHandling {
647     NewFunctionClassProto,
648     NewFunctionGivenProto
649 };
650 extern JSFunction*
651 NewFunctionWithProto(ExclusiveContext* cx, JSNative native, unsigned nargs,
652                      JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom,
653                      HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
654                      NewObjectKind newKind = GenericObject,
655                      NewFunctionProtoHandling protoHandling = NewFunctionClassProto);
656 
657 extern JSAtom*
658 IdToFunctionName(JSContext* cx, HandleId id);
659 
660 extern JSFunction*
661 DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
662                unsigned nargs, unsigned flags,
663                gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
664 
665 bool
666 FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
667 
668 extern bool
669 fun_toString(JSContext* cx, unsigned argc, Value* vp);
670 
671 extern bool
672 fun_bind(JSContext* cx, unsigned argc, Value* vp);
673 
674 /*
675  * Function extended with reserved slots for use by various kinds of functions.
676  * Most functions do not have these extensions, but enough do that efficient
677  * storage is required (no malloc'ed reserved slots).
678  */
679 class FunctionExtended : public JSFunction
680 {
681   public:
682     static const unsigned NUM_EXTENDED_SLOTS = 2;
683 
684     /* Arrow functions store their lexical new.target in the first extended slot. */
685     static const unsigned ARROW_NEWTARGET_SLOT = 0;
686 
687     static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
688 
offsetOfExtendedSlot(unsigned which)689     static inline size_t offsetOfExtendedSlot(unsigned which) {
690         MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
691         return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue);
692     }
offsetOfArrowNewTargetSlot()693     static inline size_t offsetOfArrowNewTargetSlot() {
694         return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
695     }
696 
697   private:
698     friend class JSFunction;
699 
700     /* Reserved slots available for storage by particular native functions. */
701     HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
702 };
703 
704 extern bool
705 CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
706 
707 extern JSFunction*
708 CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
709                          gc::AllocKind kind = gc::AllocKind::FUNCTION,
710                          NewObjectKind newKindArg = GenericObject,
711                          HandleObject proto = nullptr);
712 
713 // Functions whose scripts are cloned are always given singleton types.
714 extern JSFunction*
715 CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
716                        HandleObject newStaticScope,
717                        gc::AllocKind kind = gc::AllocKind::FUNCTION,
718                        HandleObject proto = nullptr);
719 
720 extern bool
721 FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
722          size_t* bodyEnd);
723 
724 } // namespace js
725 
726 inline js::FunctionExtended*
toExtended()727 JSFunction::toExtended()
728 {
729     MOZ_ASSERT(isExtended());
730     return static_cast<js::FunctionExtended*>(this);
731 }
732 
733 inline const js::FunctionExtended*
toExtended()734 JSFunction::toExtended() const
735 {
736     MOZ_ASSERT(isExtended());
737     return static_cast<const js::FunctionExtended*>(this);
738 }
739 
740 inline void
initializeExtended()741 JSFunction::initializeExtended()
742 {
743     MOZ_ASSERT(isExtended());
744 
745     MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
746     toExtended()->extendedSlots[0].init(js::UndefinedValue());
747     toExtended()->extendedSlots[1].init(js::UndefinedValue());
748 }
749 
750 inline void
initExtendedSlot(size_t which,const js::Value & val)751 JSFunction::initExtendedSlot(size_t which, const js::Value& val)
752 {
753     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
754     toExtended()->extendedSlots[which].init(val);
755 }
756 
757 inline void
setExtendedSlot(size_t which,const js::Value & val)758 JSFunction::setExtendedSlot(size_t which, const js::Value& val)
759 {
760     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
761     toExtended()->extendedSlots[which] = val;
762 }
763 
764 inline const js::Value&
getExtendedSlot(size_t which)765 JSFunction::getExtendedSlot(size_t which) const
766 {
767     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
768     return toExtended()->extendedSlots[which];
769 }
770 
771 namespace js {
772 
773 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
774 
775 template<XDRMode mode>
776 bool
777 XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
778                        HandleScript enclosingScript, MutableHandleFunction objp);
779 
780 /*
781  * Report an error that call.thisv is not compatible with the specified class,
782  * assuming that the method (clasp->name).prototype.<name of callee function>
783  * is what was called.
784  */
785 extern void
786 ReportIncompatibleMethod(JSContext* cx, CallReceiver call, const Class* clasp);
787 
788 /*
789  * Report an error that call.thisv is not an acceptable this for the callee
790  * function.
791  */
792 extern void
793 ReportIncompatible(JSContext* cx, CallReceiver call);
794 
795 bool
796 CallOrConstructBoundFunction(JSContext*, unsigned, js::Value*);
797 
798 extern const JSFunctionSpec function_methods[];
799 
800 extern bool
801 fun_apply(JSContext* cx, unsigned argc, Value* vp);
802 
803 extern bool
804 fun_call(JSContext* cx, unsigned argc, Value* vp);
805 
806 } /* namespace js */
807 
808 #ifdef DEBUG
809 namespace JS {
810 namespace detail {
811 
812 JS_PUBLIC_API(void)
813 CheckIsValidConstructible(Value calleev);
814 
815 } // namespace detail
816 } // namespace JS
817 #endif
818 
819 #endif /* jsfun_h */
820