LCOV - code coverage report
Current view: top level - js/src - jsfun.h (source / functions) Hit Total Coverage
Test: output.info Lines: 286 308 92.9 %
Date: 2017-07-14 16:53:18 Functions: 92 95 96.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : class FunctionExtended;
      21             : 
      22             : typedef JSNative           Native;
      23             : } // namespace js
      24             : 
      25             : struct JSAtomState;
      26             : 
      27             : static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET     = 2;
      28             : static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 3;
      29             : static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS       = 4;
      30             : 
      31             : static const char FunctionConstructorMedialSigils[] = ") {\n";
      32             : static const char FunctionConstructorFinalBrace[] = "\n}";
      33             : 
      34             : enum class FunctionPrefixKind {
      35             :     None,
      36             :     Get,
      37             :     Set
      38             : };
      39             : 
      40             : class JSFunction : public js::NativeObject
      41             : {
      42             :   public:
      43             :     static const js::Class class_;
      44             : 
      45             :     enum FunctionKind {
      46             :         NormalFunction = 0,
      47             :         Arrow,                      /* ES6 '(args) => body' syntax */
      48             :         Method,                     /* ES6 MethodDefinition */
      49             :         ClassConstructor,
      50             :         Getter,
      51             :         Setter,
      52             :         AsmJS,                      /* function is an asm.js module or exported function */
      53             :         FunctionKindLimit
      54             :     };
      55             : 
      56             :     enum Flags {
      57             :         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
      58             :         CONSTRUCTOR      = 0x0002,  /* function that can be called as a constructor */
      59             :         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
      60             :         BOUND_FUN        = 0x0008,  /* function was created with Function.prototype.bind. */
      61             :         HAS_GUESSED_ATOM = 0x0020,  /* function had no explicit name, but a
      62             :                                        name was guessed for it anyway */
      63             :         HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM
      64             :                                                     flag to track if atom_ already contains the
      65             :                                                     "bound " function name prefix */
      66             :         LAMBDA           = 0x0040,  /* function comes from a FunctionExpression, ArrowFunction, or
      67             :                                        Function() call (not a FunctionDeclaration or nonstandard
      68             :                                        function-statement) */
      69             :         SELF_HOSTED      = 0x0080,  /* function is self-hosted builtin and must not be
      70             :                                        decompilable nor constructible. */
      71             :         HAS_COMPILE_TIME_NAME = 0x0100, /* function had no explicit name, but a
      72             :                                            name was set by SetFunctionName
      73             :                                            at compile time */
      74             :         INTERPRETED_LAZY = 0x0200,  /* function is interpreted but doesn't have a script yet */
      75             :         RESOLVED_LENGTH  = 0x0400,  /* f.length has been resolved (see fun_resolve). */
      76             :         RESOLVED_NAME    = 0x0800,  /* f.name has been resolved (see fun_resolve). */
      77             : 
      78             :         FUNCTION_KIND_SHIFT = 13,
      79             :         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
      80             : 
      81             :         ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
      82             :         ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
      83             :         METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
      84             :         CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
      85             :         GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
      86             :         SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
      87             : 
      88             :         /* Derived Flags values for convenience: */
      89             :         NATIVE_FUN = 0,
      90             :         NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
      91             :         NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
      92             :         ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
      93             :         ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
      94             :         INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
      95             :         INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND,
      96             :         INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
      97             :         INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
      98             :         INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
      99             :         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
     100             :         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
     101             :         INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA,
     102             :         INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
     103             :         INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
     104             :         NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
     105             : 
     106             :         STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME |
     107             :                                FUNCTION_KIND_MASK
     108             :     };
     109             : 
     110             :     static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
     111             :                   "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
     112             :     static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
     113             :                   "FunctionKind doesn't fit into flags_");
     114             : 
     115             :   private:
     116             :     uint16_t        nargs_;       /* number of formal arguments
     117             :                                      (including defaults and the rest parameter unlike f.length) */
     118             :     uint16_t        flags_;       /* bitfield composed of the above Flags enum, as well as the kind */
     119             :     union U {
     120             :         class Native {
     121             :             friend class JSFunction;
     122             :             js::Native          native;       /* native method pointer or null */
     123             :             const JSJitInfo*    jitinfo;     /* Information about this function to be
     124             :                                                 used by the JIT;
     125             :                                                 use the accessor! */
     126             :         } n;
     127             :         struct Scripted {
     128             :             union {
     129             :                 JSScript* script_; /* interpreted bytecode descriptor or null;
     130             :                                       use the accessor! */
     131             :                 js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
     132             :             } s;
     133             :             JSObject*   env_;    /* environment for new activations */
     134             :         } i;
     135             :         void*           nativeOrScript;
     136             :     } u;
     137             :     js::GCPtrAtom atom_;      /* name for diagnostics and decompiling */
     138             : 
     139             :   public:
     140             :     /* Call objects must be created for each invocation of this function. */
     141       26949 :     bool needsCallObject() const {
     142       26949 :         MOZ_ASSERT(!isInterpretedLazy());
     143             : 
     144       26949 :         if (isNative())
     145           0 :             return false;
     146             : 
     147             :         // Note: this should be kept in sync with
     148             :         // FunctionBox::needsCallObjectRegardlessOfBindings().
     149       26949 :         MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() ||
     150             :                       nonLazyScript()->needsHomeObject()       ||
     151             :                       nonLazyScript()->isDerivedClassConstructor() ||
     152             :                       isStarGenerator() ||
     153             :                       isLegacyGenerator() ||
     154             :                       isAsync(),
     155             :                       nonLazyScript()->bodyScope()->hasEnvironment());
     156             : 
     157       26949 :         return nonLazyScript()->bodyScope()->hasEnvironment();
     158             :     }
     159             : 
     160             :     bool needsExtraBodyVarEnvironment() const;
     161             :     bool needsNamedLambdaEnvironment() const;
     162             : 
     163       21896 :     bool needsFunctionEnvironmentObjects() const {
     164       21896 :         return needsCallObject() || needsNamedLambdaEnvironment();
     165             :     }
     166             : 
     167        9670 :     bool needsSomeEnvironmentObject() const {
     168        9670 :         return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment();
     169             :     }
     170             : 
     171      140717 :     size_t nargs() const {
     172      140717 :         return nargs_;
     173             :     }
     174             : 
     175     2810965 :     uint16_t flags() const {
     176     2810965 :         return flags_;
     177             :     }
     178             : 
     179      164955 :     FunctionKind kind() const {
     180      164955 :         return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT);
     181             :     }
     182             : 
     183             :     /* A function can be classified as either native (C++) or interpreted (JS): */
     184      758960 :     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
     185      284256 :     bool isNative()                 const { return !isInterpreted(); }
     186             : 
     187       15960 :     bool isConstructor()            const { return flags() & CONSTRUCTOR; }
     188             : 
     189             :     /* Possible attributes of a native function: */
     190        2124 :     bool isAsmJSNative()            const { return kind() == AsmJS; }
     191             : 
     192             :     /* Possible attributes of an interpreted function: */
     193       23225 :     bool isBoundFunction()          const { return flags() & BOUND_FUN; }
     194       57875 :     bool hasCompileTimeName()       const { return flags() & HAS_COMPILE_TIME_NAME; }
     195       77169 :     bool hasGuessedAtom()           const {
     196             :         static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX,
     197             :                       "HAS_GUESSED_ATOM is unused for bound functions");
     198       77169 :         return (flags() & (HAS_GUESSED_ATOM | BOUND_FUN)) == HAS_GUESSED_ATOM;
     199             :     }
     200           6 :     bool hasBoundFunctionNamePrefix() const {
     201             :         static_assert(HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM,
     202             :                       "HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions");
     203           6 :         MOZ_ASSERT(isBoundFunction());
     204           6 :         return flags() & HAS_BOUND_FUNCTION_NAME_PREFIX;
     205             :     }
     206       49615 :     bool isLambda()                 const { return flags() & LAMBDA; }
     207      312751 :     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
     208     1022183 :     bool hasScript()                const { return flags() & INTERPRETED; }
     209             : 
     210             :     bool infallibleIsDefaultClassConstructor(JSContext* cx) const;
     211             : 
     212             :     // Arrow functions store their lexical new.target in the first extended slot.
     213       71181 :     bool isArrow()                  const { return kind() == Arrow; }
     214             :     // Every class-constructor is also a method.
     215        7945 :     bool isMethod()                 const { return kind() == Method || kind() == ClassConstructor; }
     216       70327 :     bool isClassConstructor()       const { return kind() == ClassConstructor; }
     217             : 
     218        4578 :     bool isGetter()                 const { return kind() == Getter; }
     219        4177 :     bool isSetter()                 const { return kind() == Setter; }
     220             : 
     221        6539 :     bool allowSuperProperty() const {
     222        6539 :         return isMethod() || isGetter() || isSetter();
     223             :     }
     224             : 
     225        1402 :     bool hasResolvedLength()        const { return flags() & RESOLVED_LENGTH; }
     226        1450 :     bool hasResolvedName()          const { return flags() & RESOLVED_NAME; }
     227             : 
     228       31987 :     bool isSelfHostedOrIntrinsic()  const { return flags() & SELF_HOSTED; }
     229       30918 :     bool isSelfHostedBuiltin()      const { return isSelfHostedOrIntrinsic() && !isNative(); }
     230         831 :     bool isIntrinsic()              const { return isSelfHostedOrIntrinsic() && isNative(); }
     231             : 
     232        2094 :     bool hasJITCode() const {
     233        2094 :         if (!hasScript())
     234           8 :             return false;
     235             : 
     236        2086 :         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
     237             :     }
     238             : 
     239             :     /* Compound attributes: */
     240        2599 :     bool isBuiltin() const {
     241        2599 :         return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
     242             :     }
     243             : 
     244       49611 :     bool isNamedLambda() const {
     245       49611 :         return isLambda() && displayAtom() && !hasCompileTimeName() && !hasGuessedAtom();
     246             :     }
     247             : 
     248           0 :     bool hasLexicalThis() const {
     249           0 :         return isArrow() || nonLazyScript()->isGeneratorExp();
     250             :     }
     251             : 
     252             :     bool isBuiltinFunctionConstructor();
     253             :     bool needsPrototypeProperty();
     254             : 
     255             :     /* Returns the strictness of this function, which must be interpreted. */
     256         201 :     bool strict() const {
     257         201 :         MOZ_ASSERT(isInterpreted());
     258         201 :         return isInterpretedLazy() ? lazyScript()->strict() : nonLazyScript()->strict();
     259             :     }
     260             : 
     261      161524 :     void setFlags(uint16_t flags) {
     262      161524 :         this->flags_ = flags;
     263      161524 :     }
     264           3 :     void setKind(FunctionKind kind) {
     265           3 :         this->flags_ &= ~FUNCTION_KIND_MASK;
     266           3 :         this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
     267           3 :     }
     268             : 
     269             :     // Make the function constructible.
     270         216 :     void setIsConstructor() {
     271         216 :         MOZ_ASSERT(!isConstructor());
     272         216 :         MOZ_ASSERT(isSelfHostedBuiltin());
     273         216 :         flags_ |= CONSTRUCTOR;
     274         216 :     }
     275             : 
     276           3 :     void setIsClassConstructor() {
     277           3 :         MOZ_ASSERT(!isClassConstructor());
     278           3 :         MOZ_ASSERT(isConstructor());
     279             : 
     280           3 :         setKind(ClassConstructor);
     281           3 :     }
     282             : 
     283             :     // Can be called multiple times by the parser.
     284      122443 :     void setArgCount(uint16_t nargs) {
     285      122443 :         this->nargs_ = nargs;
     286      122443 :     }
     287             : 
     288         330 :     void setIsBoundFunction() {
     289         330 :         MOZ_ASSERT(!isBoundFunction());
     290         330 :         flags_ |= BOUND_FUN;
     291         330 :     }
     292             : 
     293       21248 :     void setIsSelfHostedBuiltin() {
     294       21248 :         MOZ_ASSERT(isInterpreted());
     295       21248 :         MOZ_ASSERT(!isSelfHostedBuiltin());
     296       21248 :         flags_ |= SELF_HOSTED;
     297             :         // Self-hosted functions should not be constructable.
     298       21248 :         flags_ &= ~CONSTRUCTOR;
     299       21248 :     }
     300         831 :     void setIsIntrinsic() {
     301         831 :         MOZ_ASSERT(isNative());
     302         831 :         MOZ_ASSERT(!isIntrinsic());
     303         831 :         flags_ |= SELF_HOSTED;
     304         831 :     }
     305             : 
     306             :     void setArrow() {
     307             :         setKind(Arrow);
     308             :     }
     309             : 
     310         371 :     void setResolvedLength() {
     311         371 :         flags_ |= RESOLVED_LENGTH;
     312         371 :     }
     313             : 
     314         382 :     void setResolvedName() {
     315         382 :         flags_ |= RESOLVED_NAME;
     316         382 :     }
     317             : 
     318             :     void setAsyncKind(js::FunctionAsyncKind asyncKind) {
     319             :         if (isInterpretedLazy())
     320             :             lazyScript()->setAsyncKind(asyncKind);
     321             :         else
     322             :             nonLazyScript()->setAsyncKind(asyncKind);
     323             :     }
     324             : 
     325             :     static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
     326             :                                     js::MutableHandleValue v);
     327             : 
     328             :     static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
     329             :                                   js::MutableHandleAtom v);
     330             : 
     331       45971 :     JSAtom* explicitName() const {
     332       45971 :         return (hasCompileTimeName() || hasGuessedAtom()) ? nullptr : atom_.get();
     333             :     }
     334         725 :     JSAtom* explicitOrCompileTimeName() const {
     335         725 :         return hasGuessedAtom() ? nullptr : atom_.get();
     336             :     }
     337             : 
     338      117543 :     void initAtom(JSAtom* atom) {
     339      117543 :         MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
     340      117546 :         atom_.init(atom);
     341      117552 :     }
     342             : 
     343         393 :     void setAtom(JSAtom* atom) {
     344         393 :         MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
     345         393 :         atom_ = atom;
     346         393 :     }
     347             : 
     348       69595 :     JSAtom* displayAtom() const {
     349       69595 :         return atom_;
     350             :     }
     351             : 
     352         389 :     void setCompileTimeName(JSAtom* atom) {
     353         389 :         MOZ_ASSERT(!atom_);
     354         389 :         MOZ_ASSERT(atom);
     355         389 :         MOZ_ASSERT(!hasGuessedAtom());
     356         389 :         MOZ_ASSERT(!isClassConstructor());
     357         389 :         MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
     358         389 :         atom_ = atom;
     359         389 :         flags_ |= HAS_COMPILE_TIME_NAME;
     360         389 :     }
     361          10 :     JSAtom* compileTimeName() const {
     362          10 :         MOZ_ASSERT(hasCompileTimeName());
     363          10 :         MOZ_ASSERT(atom_);
     364          10 :         return atom_;
     365             :     }
     366             : 
     367         683 :     void setGuessedAtom(JSAtom* atom) {
     368         683 :         MOZ_ASSERT(!atom_);
     369         683 :         MOZ_ASSERT(atom);
     370         683 :         MOZ_ASSERT(!hasCompileTimeName());
     371         683 :         MOZ_ASSERT(!hasGuessedAtom());
     372         683 :         MOZ_ASSERT(!isBoundFunction());
     373         683 :         MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
     374         683 :         atom_ = atom;
     375         683 :         flags_ |= HAS_GUESSED_ATOM;
     376         683 :     }
     377           6 :     void clearGuessedAtom() {
     378           6 :         MOZ_ASSERT(hasGuessedAtom());
     379           6 :         MOZ_ASSERT(!isBoundFunction());
     380           6 :         MOZ_ASSERT(atom_);
     381           6 :         atom_ = nullptr;
     382           6 :         flags_ &= ~HAS_GUESSED_ATOM;
     383           6 :     }
     384             : 
     385           3 :     void setPrefixedBoundFunctionName(JSAtom* atom) {
     386           3 :         MOZ_ASSERT(!hasBoundFunctionNamePrefix());
     387           3 :         MOZ_ASSERT(atom);
     388           3 :         flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX;
     389           3 :         atom_ = atom;
     390           3 :     }
     391             : 
     392             :     /* uint16_t representation bounds number of call object dynamic slots. */
     393             :     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
     394             : 
     395             :     /*
     396             :      * For an interpreted function, accessors for the initial scope object of
     397             :      * activations (stack frames) of the function.
     398             :      */
     399       13720 :     JSObject* environment() const {
     400       13720 :         MOZ_ASSERT(isInterpreted());
     401       13720 :         return u.i.env_;
     402             :     }
     403             : 
     404        1411 :     void setEnvironment(JSObject* obj) {
     405        1411 :         MOZ_ASSERT(isInterpreted());
     406        1411 :         *reinterpret_cast<js::GCPtrObject*>(&u.i.env_) = obj;
     407        1411 :     }
     408             : 
     409       58922 :     void initEnvironment(JSObject* obj) {
     410       58922 :         MOZ_ASSERT(isInterpreted());
     411       58922 :         reinterpret_cast<js::GCPtrObject*>(&u.i.env_)->init(obj);
     412       58923 :     }
     413             : 
     414             :     void unsetEnvironment() {
     415             :         setEnvironment(nullptr);
     416             :     }
     417             : 
     418             :   public:
     419         383 :     static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
     420         105 :     static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
     421         639 :     static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
     422          10 :     static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
     423             : 
     424             :     static bool createScriptForLazilyInterpretedFunction(JSContext* cx, js::HandleFunction fun);
     425             :     void maybeRelazify(JSRuntime* rt);
     426             : 
     427             :     // Function Scripts
     428             :     //
     429             :     // Interpreted functions may either have an explicit JSScript (hasScript())
     430             :     // or be lazy with sufficient information to construct the JSScript if
     431             :     // necessary (isInterpretedLazy()).
     432             :     //
     433             :     // A lazy function will have a LazyScript if the function came from parsed
     434             :     // source, or nullptr if the function is a clone of a self hosted function.
     435             :     //
     436             :     // There are several methods to get the script of an interpreted function:
     437             :     //
     438             :     // - For all interpreted functions, getOrCreateScript() will get the
     439             :     //   JSScript, delazifying the function if necessary. This is the safest to
     440             :     //   use, but has extra checks, requires a cx and may trigger a GC.
     441             :     //
     442             :     // - For inlined functions which may have a LazyScript but whose JSScript
     443             :     //   is known to exist, existingScript() will get the script and delazify
     444             :     //   the function if necessary. If the function should not be delazified,
     445             :     //   use existingScriptNonDelazifying().
     446             :     //
     447             :     // - For functions known to have a JSScript, nonLazyScript() will get it.
     448             : 
     449       30198 :     static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
     450       30198 :         MOZ_ASSERT(fun->isInterpreted());
     451       30198 :         MOZ_ASSERT(cx);
     452       30198 :         if (fun->isInterpretedLazy()) {
     453        2249 :             if (!createScriptForLazilyInterpretedFunction(cx, fun))
     454           0 :                 return nullptr;
     455        2249 :             return fun->nonLazyScript();
     456             :         }
     457       27949 :         return fun->nonLazyScript();
     458             :     }
     459             : 
     460        4700 :     JSScript* existingScriptNonDelazifying() const {
     461        4700 :         MOZ_ASSERT(isInterpreted());
     462        4700 :         if (isInterpretedLazy()) {
     463             :             // Get the script from the canonical function. Ion used the
     464             :             // canonical function to inline the script and because it has
     465             :             // Baseline code it has not been relazified. Note that we can't
     466             :             // use lazyScript->script_ here as it may be null in some cases,
     467             :             // see bug 976536.
     468           0 :             js::LazyScript* lazy = lazyScript();
     469           0 :             JSFunction* fun = lazy->functionNonDelazifying();
     470           0 :             MOZ_ASSERT(fun);
     471           0 :             return fun->nonLazyScript();
     472             :         }
     473        4700 :         return nonLazyScript();
     474             :     }
     475             : 
     476           0 :     JSScript* existingScript() {
     477           0 :         MOZ_ASSERT(isInterpreted());
     478           0 :         if (isInterpretedLazy()) {
     479           0 :             if (shadowZone()->needsIncrementalBarrier())
     480           0 :                 js::LazyScript::writeBarrierPre(lazyScript());
     481           0 :             JSScript* script = existingScriptNonDelazifying();
     482           0 :             flags_ &= ~INTERPRETED_LAZY;
     483           0 :             flags_ |= INTERPRETED;
     484           0 :             initScript(script);
     485             :         }
     486           0 :         return nonLazyScript();
     487             :     }
     488             : 
     489             :     // The state of a JSFunction whose script errored out during bytecode
     490             :     // compilation. Such JSFunctions are only reachable via GC iteration and
     491             :     // not from script.
     492      718722 :     bool hasUncompiledScript() const {
     493      718722 :         MOZ_ASSERT(hasScript());
     494      718721 :         return !u.i.s.script_;
     495             :     }
     496             : 
     497      699102 :     JSScript* nonLazyScript() const {
     498      699102 :         MOZ_ASSERT(!hasUncompiledScript());
     499      699101 :         return u.i.s.script_;
     500             :     }
     501             : 
     502             :     static bool getLength(JSContext* cx, js::HandleFunction fun, uint16_t* length);
     503             : 
     504       25485 :     js::LazyScript* lazyScript() const {
     505       25485 :         MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
     506       25485 :         return u.i.s.lazy_;
     507             :     }
     508             : 
     509        9869 :     js::LazyScript* lazyScriptOrNull() const {
     510        9869 :         MOZ_ASSERT(isInterpretedLazy());
     511        9869 :         return u.i.s.lazy_;
     512             :     }
     513             : 
     514      107002 :     js::GeneratorKind generatorKind() const {
     515      107002 :         if (!isInterpreted())
     516        1516 :             return js::NotGenerator;
     517      105486 :         if (hasScript())
     518      103191 :             return nonLazyScript()->generatorKind();
     519        2295 :         if (js::LazyScript* lazy = lazyScriptOrNull())
     520        2295 :             return lazy->generatorKind();
     521           0 :         MOZ_ASSERT(isSelfHostedBuiltin());
     522           0 :         return js::NotGenerator;
     523             :     }
     524             : 
     525       39230 :     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
     526             : 
     527       67512 :     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
     528             : 
     529         260 :     js::FunctionAsyncKind asyncKind() const {
     530         260 :         return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
     531             :     }
     532             : 
     533       66317 :     bool isAsync() const {
     534       66317 :         if (isInterpretedLazy())
     535        1680 :             return lazyScript()->isAsync();
     536       64637 :         if (hasScript())
     537       63121 :             return nonLazyScript()->isAsync();
     538        1516 :         return false;
     539             :     }
     540             : 
     541        3998 :     void setScript(JSScript* script_) {
     542        3998 :         mutableScript() = script_;
     543        3998 :     }
     544             : 
     545       58158 :     void initScript(JSScript* script_) {
     546       58158 :         mutableScript().init(script_);
     547       58158 :     }
     548             : 
     549        2249 :     void setUnlazifiedScript(JSScript* script) {
     550        2249 :         MOZ_ASSERT(isInterpretedLazy());
     551        2249 :         if (lazyScriptOrNull()) {
     552             :             // Trigger a pre barrier on the lazy script being overwritten.
     553        1693 :             js::LazyScript::writeBarrierPre(lazyScriptOrNull());
     554        1693 :             if (!lazyScript()->maybeScript())
     555        1412 :                 lazyScript()->initScript(script);
     556             :         }
     557        2249 :         flags_ &= ~INTERPRETED_LAZY;
     558        2249 :         flags_ |= INTERPRETED;
     559        2249 :         initScript(script);
     560        2249 :     }
     561             : 
     562       24481 :     void initLazyScript(js::LazyScript* lazy) {
     563       24481 :         MOZ_ASSERT(isInterpreted());
     564       24481 :         flags_ &= ~INTERPRETED;
     565       24481 :         flags_ |= INTERPRETED_LAZY;
     566       24481 :         u.i.s.lazy_ = lazy;
     567       24481 :     }
     568             : 
     569       34815 :     JSNative native() const {
     570       34815 :         MOZ_ASSERT(isNative());
     571       34815 :         return u.n.native;
     572             :     }
     573             : 
     574        6035 :     JSNative maybeNative() const {
     575        6035 :         return isInterpreted() ? nullptr : native();
     576             :     }
     577             : 
     578       48403 :     void initNative(js::Native native, const JSJitInfo* jitinfo) {
     579       48403 :         MOZ_ASSERT(native);
     580       48403 :         u.n.native = native;
     581       48403 :         u.n.jitinfo = jitinfo;
     582       48403 :     }
     583             : 
     584       25561 :     const JSJitInfo* jitInfo() const {
     585       25561 :         MOZ_ASSERT(isNative());
     586       25561 :         return u.n.jitinfo;
     587             :     }
     588             : 
     589       16222 :     void setJitInfo(const JSJitInfo* data) {
     590       16222 :         MOZ_ASSERT(isNative());
     591       16222 :         u.n.jitinfo = data;
     592       16222 :     }
     593             : 
     594             :     bool isDerivedClassConstructor();
     595             : 
     596         181 :     static unsigned offsetOfNativeOrScript() {
     597             :         static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
     598             :                       "native and script pointers must be in the same spot "
     599             :                       "for offsetOfNativeOrScript() have any sense");
     600             :         static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
     601             :                       "U::nativeOrScript must be at the same offset as "
     602             :                       "native");
     603             : 
     604         181 :         return offsetof(JSFunction, u.nativeOrScript);
     605             :     }
     606             : 
     607           2 :     static unsigned offsetOfJitInfo() {
     608           2 :         return offsetof(JSFunction, u.n.jitinfo);
     609             :     }
     610             : 
     611             :     inline void trace(JSTracer* trc);
     612             : 
     613             :     /* Bound function accessors. */
     614             : 
     615             :     JSObject* getBoundFunctionTarget() const;
     616             :     const js::Value& getBoundFunctionThis() const;
     617             :     const js::Value& getBoundFunctionArgument(unsigned which) const;
     618             :     size_t getBoundFunctionArgumentCount() const;
     619             : 
     620             :     /*
     621             :      * Used to mark bound functions as such and make them constructible if the
     622             :      * target is. Also assigns the prototype and sets the name and correct length.
     623             :      */
     624             :     static bool finishBoundFunctionInit(JSContext* cx, js::HandleFunction bound,
     625             :                                         js::HandleObject targetObj, int32_t argCount);
     626             : 
     627             :   private:
     628       62155 :     js::GCPtrScript& mutableScript() {
     629       62155 :         MOZ_ASSERT(hasScript());
     630       62155 :         return *(js::GCPtrScript*)&u.i.s.script_;
     631             :     }
     632             : 
     633             :     inline js::FunctionExtended* toExtended();
     634             :     inline const js::FunctionExtended* toExtended() const;
     635             : 
     636             :   public:
     637      420930 :     inline bool isExtended() const {
     638      420930 :         bool extended = !!(flags() & EXTENDED);
     639      420930 :         MOZ_ASSERT_IF(isTenured(),
     640             :                       extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED));
     641      420928 :         return extended;
     642             :     }
     643             : 
     644             :     /*
     645             :      * Accessors for data stored in extended functions. Use setExtendedSlot if
     646             :      * the function has already been initialized. Otherwise use
     647             :      * initExtendedSlot.
     648             :      */
     649             :     inline void initializeExtended();
     650             :     inline void initExtendedSlot(size_t which, const js::Value& val);
     651             :     inline void setExtendedSlot(size_t which, const js::Value& val);
     652             :     inline const js::Value& getExtendedSlot(size_t which) const;
     653             : 
     654             :     /* Constructs a new type for the function if necessary. */
     655             :     static bool setTypeForScriptedFunction(JSContext* cx, js::HandleFunction fun,
     656             :                                            bool singleton = false);
     657             : 
     658             :     /* GC support. */
     659       23845 :     js::gc::AllocKind getAllocKind() const {
     660             :         static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
     661             :                       "extended/non-extended AllocKinds have to be different "
     662             :                       "for getAllocKind() to have a reason to exist");
     663             : 
     664       23845 :         js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
     665       23845 :         if (isExtended())
     666       11543 :             kind = js::gc::AllocKind::FUNCTION_EXTENDED;
     667       23845 :         MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
     668       23845 :         return kind;
     669             :     }
     670             : };
     671             : 
     672             : static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
     673             :               "shadow interface must match actual interface");
     674             : 
     675             : extern JSString*
     676             : fun_toStringHelper(JSContext* cx, js::HandleObject obj, unsigned indent);
     677             : 
     678             : namespace js {
     679             : 
     680             : extern bool
     681             : Function(JSContext* cx, unsigned argc, Value* vp);
     682             : 
     683             : extern bool
     684             : Generator(JSContext* cx, unsigned argc, Value* vp);
     685             : 
     686             : extern bool
     687             : AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
     688             : 
     689             : extern bool
     690             : AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
     691             : 
     692             : // Allocate a new function backed by a JSNative.  Note that by default this
     693             : // creates a singleton object.
     694             : extern JSFunction*
     695             : NewNativeFunction(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
     696             :                   gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
     697             :                   NewObjectKind newKind = SingletonObject);
     698             : 
     699             : // Allocate a new constructor backed by a JSNative.  Note that by default this
     700             : // creates a singleton object.
     701             : extern JSFunction*
     702             : NewNativeConstructor(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
     703             :                      gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
     704             :                      NewObjectKind newKind = SingletonObject,
     705             :                      JSFunction::Flags flags = JSFunction::NATIVE_CTOR);
     706             : 
     707             : // Allocate a new scripted function.  If enclosingEnv is null, the
     708             : // global will be used.  In all cases the parent of the resulting object will be
     709             : // the global.
     710             : extern JSFunction*
     711             : NewScriptedFunction(JSContext* cx, unsigned nargs, JSFunction::Flags flags,
     712             :                     HandleAtom atom, HandleObject proto = nullptr,
     713             :                     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
     714             :                     NewObjectKind newKind = GenericObject,
     715             :                     HandleObject enclosingEnv = nullptr);
     716             : 
     717             : // By default, if proto is nullptr, Function.prototype is used instead.i
     718             : // If protoHandling is NewFunctionExactProto, and proto is nullptr, the created
     719             : // function will use nullptr as its [[Prototype]] instead. If
     720             : // enclosingEnv is null, the function will have a null environment()
     721             : // (yes, null, not the global).  In all cases, the global will be used as the
     722             : // parent.
     723             : 
     724             : enum NewFunctionProtoHandling {
     725             :     NewFunctionClassProto,
     726             :     NewFunctionGivenProto
     727             : };
     728             : extern JSFunction*
     729             : NewFunctionWithProto(JSContext* cx, JSNative native, unsigned nargs,
     730             :                      JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom,
     731             :                      HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
     732             :                      NewObjectKind newKind = GenericObject,
     733             :                      NewFunctionProtoHandling protoHandling = NewFunctionClassProto);
     734             : 
     735             : extern JSAtom*
     736             : IdToFunctionName(JSContext* cx, HandleId id,
     737             :                  FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
     738             : 
     739             : extern JSAtom*
     740             : NameToFunctionName(JSContext* cx, HandleAtom name,
     741             :                    FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
     742             : 
     743             : extern bool
     744             : SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
     745             :                            FunctionPrefixKind prefixKind);
     746             : 
     747             : extern JSFunction*
     748             : DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
     749             :                unsigned nargs, unsigned flags,
     750             :                gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
     751             : 
     752             : bool
     753             : FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
     754             : 
     755             : extern bool
     756             : fun_toString(JSContext* cx, unsigned argc, Value* vp);
     757             : 
     758             : struct WellKnownSymbols;
     759             : 
     760             : extern bool
     761             : FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols);
     762             : 
     763             : extern bool
     764             : fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
     765             : 
     766             : /*
     767             :  * Function extended with reserved slots for use by various kinds of functions.
     768             :  * Most functions do not have these extensions, but enough do that efficient
     769             :  * storage is required (no malloc'ed reserved slots).
     770             :  */
     771             : class FunctionExtended : public JSFunction
     772             : {
     773             :   public:
     774             :     static const unsigned NUM_EXTENDED_SLOTS = 2;
     775             : 
     776             :     /* Arrow functions store their lexical new.target in the first extended slot. */
     777             :     static const unsigned ARROW_NEWTARGET_SLOT = 0;
     778             : 
     779             :     static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
     780             : 
     781             :     /*
     782             :      * Exported asm.js/wasm functions store their WasmInstanceObject in the
     783             :      * first slot.
     784             :      */
     785             :     static const unsigned WASM_INSTANCE_SLOT = 0;
     786             : 
     787             :     /*
     788             :      * wasm/asm.js exported functions store the function index of the exported
     789             :      * function in the original module.
     790             :      */
     791             :     static const unsigned WASM_FUNC_INDEX_SLOT = 1;
     792             : 
     793             :     /*
     794             :      * asm.js module functions store their WasmModuleObject in the first slot.
     795             :      */
     796             :     static const unsigned ASMJS_MODULE_SLOT = 0;
     797             : 
     798             : 
     799           7 :     static inline size_t offsetOfExtendedSlot(unsigned which) {
     800           7 :         MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
     801           7 :         return offsetof(FunctionExtended, extendedSlots) + which * sizeof(GCPtrValue);
     802             :     }
     803           7 :     static inline size_t offsetOfArrowNewTargetSlot() {
     804           7 :         return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
     805             :     }
     806           0 :     static inline size_t offsetOfMethodHomeObjectSlot() {
     807           0 :         return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
     808             :     }
     809             : 
     810             :   private:
     811             :     friend class JSFunction;
     812             : 
     813             :     /* Reserved slots available for storage by particular native functions. */
     814             :     GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS];
     815             : };
     816             : 
     817             : extern bool
     818             : CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
     819             : 
     820             : extern JSFunction*
     821             : CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
     822             :                          gc::AllocKind kind = gc::AllocKind::FUNCTION,
     823             :                          NewObjectKind newKindArg = GenericObject,
     824             :                          HandleObject proto = nullptr);
     825             : 
     826             : // Functions whose scripts are cloned are always given singleton types.
     827             : extern JSFunction*
     828             : CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
     829             :                        HandleScope newScope,
     830             :                        gc::AllocKind kind = gc::AllocKind::FUNCTION,
     831             :                        HandleObject proto = nullptr);
     832             : 
     833             : } // namespace js
     834             : 
     835             : inline js::FunctionExtended*
     836      237674 : JSFunction::toExtended()
     837             : {
     838      237674 :     MOZ_ASSERT(isExtended());
     839      237674 :     return static_cast<js::FunctionExtended*>(this);
     840             : }
     841             : 
     842             : inline const js::FunctionExtended*
     843       80564 : JSFunction::toExtended() const
     844             : {
     845       80564 :     MOZ_ASSERT(isExtended());
     846       80564 :     return static_cast<const js::FunctionExtended*>(this);
     847             : }
     848             : 
     849             : inline void
     850       42135 : JSFunction::initializeExtended()
     851             : {
     852       42135 :     MOZ_ASSERT(isExtended());
     853             : 
     854       42135 :     MOZ_ASSERT(mozilla::ArrayLength(toExtended()->extendedSlots) == 2);
     855       42135 :     toExtended()->extendedSlots[0].init(js::UndefinedValue());
     856       42135 :     toExtended()->extendedSlots[1].init(js::UndefinedValue());
     857       42135 : }
     858             : 
     859             : inline void
     860       15144 : JSFunction::initExtendedSlot(size_t which, const js::Value& val)
     861             : {
     862       15144 :     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
     863       15144 :     js::CheckEdgeIsNotBlackToGray(this, val);
     864       15144 :     MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
     865       15144 :     toExtended()->extendedSlots[which].init(val);
     866       15144 : }
     867             : 
     868             : inline void
     869       33691 : JSFunction::setExtendedSlot(size_t which, const js::Value& val)
     870             : {
     871       33691 :     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
     872       33691 :     js::CheckEdgeIsNotBlackToGray(this, val);
     873       33691 :     MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
     874       33691 :     toExtended()->extendedSlots[which] = val;
     875       33691 : }
     876             : 
     877             : inline const js::Value&
     878       40282 : JSFunction::getExtendedSlot(size_t which) const
     879             : {
     880       40282 :     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
     881       40282 :     return toExtended()->extendedSlots[which];
     882             : }
     883             : 
     884             : namespace js {
     885             : 
     886             : JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
     887             : 
     888             : template<XDRMode mode>
     889             : bool
     890             : XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
     891             :                        HandleScriptSource sourceObject, MutableHandleFunction objp);
     892             : 
     893             : /*
     894             :  * Report an error that call.thisv is not compatible with the specified class,
     895             :  * assuming that the method (clasp->name).prototype.<name of callee function>
     896             :  * is what was called.
     897             :  */
     898             : extern void
     899             : ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, const Class* clasp);
     900             : 
     901             : /*
     902             :  * Report an error that call.thisv is not an acceptable this for the callee
     903             :  * function.
     904             :  */
     905             : extern void
     906             : ReportIncompatible(JSContext* cx, const CallArgs& args);
     907             : 
     908             : extern const JSFunctionSpec function_methods[];
     909             : extern const JSFunctionSpec function_selfhosted_methods[];
     910             : 
     911             : extern bool
     912             : fun_apply(JSContext* cx, unsigned argc, Value* vp);
     913             : 
     914             : extern bool
     915             : fun_call(JSContext* cx, unsigned argc, Value* vp);
     916             : 
     917             : } /* namespace js */
     918             : 
     919             : #ifdef DEBUG
     920             : namespace JS {
     921             : namespace detail {
     922             : 
     923             : JS_PUBLIC_API(void)
     924             : CheckIsValidConstructible(const Value& calleev);
     925             : 
     926             : } // namespace detail
     927             : } // namespace JS
     928             : #endif
     929             : 
     930             : #endif /* jsfun_h */

Generated by: LCOV version 1.13