tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

JSFunction.h (35913B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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 vm_JSFunction_h
      8 #define vm_JSFunction_h
      9 
     10 /*
     11 * JS function definitions.
     12 */
     13 
     14 #include <string_view>
     15 
     16 #include "jstypes.h"
     17 
     18 #include "gc/Policy.h"
     19 #include "js/shadow/Function.h"        // JS::shadow::Function
     20 #include "vm/FunctionFlags.h"          // FunctionFlags
     21 #include "vm/FunctionPrefixKind.h"     // FunctionPrefixKind
     22 #include "vm/GeneratorAndAsyncKind.h"  // GeneratorKind, FunctionAsyncKind
     23 #include "vm/JSAtomUtils.h"            // AtomIsMarked
     24 #include "vm/JSObject.h"
     25 #include "vm/JSScript.h"
     26 #include "wasm/WasmTypeDef.h"
     27 
     28 class JSJitInfo;
     29 
     30 namespace js {
     31 
     32 class FunctionExtended;
     33 class JS_PUBLIC_API GenericPrinter;
     34 class JSONPrinter;
     35 struct SelfHostedLazyScript;
     36 
     37 using Native = JSNative;
     38 
     39 static constexpr std::string_view FunctionConstructorMedialSigils = ") {\n";
     40 static constexpr std::string_view FunctionConstructorFinalBrace = "\n}";
     41 
     42 // JSFunctions can have one of two classes:
     43 extern const JSClass FunctionClass;
     44 extern const JSClass ExtendedFunctionClass;
     45 
     46 namespace wasm {
     47 
     48 class Instance;
     49 
     50 }  // namespace wasm
     51 }  // namespace js
     52 
     53 class JSFunction : public js::NativeObject {
     54 public:
     55  static_assert(sizeof(js::FunctionFlags) == sizeof(uint16_t));
     56  static constexpr size_t ArgCountShift = 16;
     57  static constexpr size_t FlagsMask = js::BitMask(ArgCountShift);
     58  static constexpr size_t ArgCountMask = js::BitMask(16) << ArgCountShift;
     59 
     60  enum {
     61    /*
     62     * Bitfield composed of FunctionFlags and argument count, stored as a
     63     * PrivateUint32Value.
     64     *
     65     * If any of these flags needs to be accessed in off-thread JIT compilation,
     66     * copy it to js::jit::WrappedFunction.
     67     */
     68    FlagsAndArgCountSlot,
     69 
     70    /*
     71     * For native functions, the native method pointer stored as a private
     72     * value, or undefined.
     73     *
     74     * For interpreted functions, the environment object for new activations or
     75     * null.
     76     */
     77    NativeFuncOrInterpretedEnvSlot,
     78 
     79    /*
     80     * For native functions this is one of:
     81     *
     82     *  - JSJitInfo* to be used by the JIT, only used if isBuiltinNative() for
     83     *    builtin natives
     84     *
     85     *  - wasm function index for wasm/asm.js without a jit entry. Always has
     86     *    the low bit set to ensure it's never identical to a BaseScript*
     87     *    pointer
     88     *
     89     *  - a native JIT entry (used for Wasm and TrampolineNative functions)
     90     *
     91     * The JIT depends on none of the above being a valid BaseScript pointer.
     92     *
     93     * For interpreted functions this is either a BaseScript or the
     94     * SelfHostedLazyScript pointer.
     95     *
     96     * These are all stored as private values, because the JIT assumes that it
     97     * can access the SelfHostedLazyScript and BaseScript pointer in the same
     98     * way.
     99     */
    100    NativeJitInfoOrInterpretedScriptSlot,
    101 
    102    // The `atom_` field can have different meanings depending on the function
    103    // type and flags. It is used for diagnostics, decompiling, and
    104    //
    105    //   a. If LAZY_ACCESSOR_NAME is set, to store the initial value of the
    106    //      unprefixed part of "name" property of a accessor function.
    107    //      But also see RESOLVED_NAME.
    108    //   b. If HAS_GUESSED_ATOM is not set, to store the initial value of the
    109    //      "name" property of functions. But also see RESOLVED_NAME.
    110    //   c. If HAS_GUESSED_ATOM is set, `atom_` is only used for diagnostics,
    111    //      but must not be used for the "name" property.
    112    //   d. If HAS_INFERRED_NAME is set, the function wasn't given an explicit
    113    //      name in the source text, e.g. `function fn(){}`, but instead it
    114    //      was inferred based on how the function was defined in the source
    115    //      text. The exact name inference rules are defined in the ECMAScript
    116    //      specification.
    117    //      Name inference can happen at compile-time, for example in
    118    //      `var fn = function(){}`, or it can happen at runtime, for example
    119    //      in `var o = {[Symbol.iterator]: function(){}}`. When it happens at
    120    //      compile-time, the HAS_INFERRED_NAME is set directly in the
    121    //      bytecode emitter, when it happens at runtime, the flag is set when
    122    //      evaluating the JSOp::SetFunName bytecode.
    123    //   e. HAS_GUESSED_ATOM,  HAS_INFERRED_NAME, and LAZY_ACCESSOR_NAME are
    124    //      mutually exclusive and cannot be set at the same time.
    125    //   f. `atom_` can be null if neither an explicit, nor inferred, nor a
    126    //      guessed name was set.
    127    //
    128    // Self-hosted functions have two names. For example, Array.prototype.sort
    129    // has the standard name "sort", but the implementation in Array.js is named
    130    // "ArraySort".
    131    //
    132    // -   In the self-hosting realm, these functions have `_atom` set to the
    133    //     implementation name.
    134    //
    135    // -   When we clone these functions into normal realms, we set `_atom` to
    136    //     the standard name. (The self-hosted name is also stored on the clone,
    137    //     in another slot; see GetClonedSelfHostedFunctionName().)
    138    AtomSlot,
    139 
    140    SlotCount
    141  };
    142 
    143 private:
    144  using FunctionFlags = js::FunctionFlags;
    145 
    146 public:
    147  static inline JSFunction* create(JSContext* cx, js::gc::AllocKind kind,
    148                                   js::gc::Heap heap,
    149                                   js::Handle<js::SharedShape*> shape,
    150                                   js::gc::AllocSite* site = nullptr);
    151 
    152  /* Call objects must be created for each invocation of this function. */
    153  bool needsCallObject() const;
    154 
    155  bool needsExtraBodyVarEnvironment() const;
    156  bool needsNamedLambdaEnvironment() const;
    157 
    158  bool needsFunctionEnvironmentObjects() const {
    159    bool res = nonLazyScript()->needsFunctionEnvironmentObjects();
    160    MOZ_ASSERT(res == (needsCallObject() || needsNamedLambdaEnvironment()));
    161    return res;
    162  }
    163 
    164  bool needsSomeEnvironmentObject() const {
    165    return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment();
    166  }
    167 
    168  uint32_t flagsAndArgCountRaw() const {
    169    return getFixedSlot(FlagsAndArgCountSlot).toPrivateUint32();
    170  }
    171 
    172  void initFlagsAndArgCount() {
    173    initFixedSlot(FlagsAndArgCountSlot, JS::PrivateUint32Value(0));
    174  }
    175 
    176  size_t nargs() const { return flagsAndArgCountRaw() >> ArgCountShift; }
    177 
    178  FunctionFlags flags() const {
    179    return FunctionFlags(uint16_t(flagsAndArgCountRaw() & FlagsMask));
    180  }
    181 
    182  FunctionFlags::FunctionKind kind() const { return flags().kind(); }
    183 
    184 #ifdef DEBUG
    185  void assertFunctionKindIntegrity() { flags().assertFunctionKindIntegrity(); }
    186 #endif
    187 
    188  /* A function can be classified as either native (C++) or interpreted (JS): */
    189  bool isInterpreted() const { return flags().isInterpreted(); }
    190  bool isNativeFun() const { return flags().isNativeFun(); }
    191 
    192  bool isConstructor() const { return flags().isConstructor(); }
    193 
    194  bool isNonBuiltinConstructor() const {
    195    return flags().isNonBuiltinConstructor();
    196  }
    197 
    198  /* Possible attributes of a native function: */
    199  bool isAsmJSNative() const { return flags().isAsmJSNative(); }
    200 
    201  // A WebAssembly "Exported Function" is the spec name for the JS function
    202  // objects created to wrap wasm functions. This predicate returns false
    203  // for asm.js functions which are semantically just normal JS functions
    204  // (even if they are implemented via wasm under the hood). The accessor
    205  // functions for extracting the instance and func-index of a wasm function
    206  // can be used for both wasm and asm.js, however.
    207  bool isWasm() const { return flags().isWasm(); }
    208  bool isWasmWithJitEntry() const { return flags().isWasmWithJitEntry(); }
    209 
    210  bool isNativeWithJitEntry() const { return flags().isNativeWithJitEntry(); }
    211  bool isNativeWithoutJitEntry() const {
    212    return flags().isNativeWithoutJitEntry();
    213  }
    214  bool isBuiltinNative() const { return flags().isBuiltinNative(); }
    215 
    216  bool hasJitEntry() const { return flags().hasJitEntry(); }
    217 
    218  /* Possible attributes of an interpreted function: */
    219  bool hasInferredName() const { return flags().hasInferredName(); }
    220  bool hasGuessedAtom() const { return flags().hasGuessedAtom(); }
    221 
    222  bool isLambda() const { return flags().isLambda(); }
    223 
    224  // These methods determine which kind of script we hold.
    225  //
    226  // For live JSFunctions the pointer values will always be non-null, but due to
    227  // partial initialization the GC (and other features that scan the heap
    228  // directly) may still return a null pointer.
    229  bool hasSelfHostedLazyScript() const {
    230    return flags().hasSelfHostedLazyScript();
    231  }
    232  bool hasBaseScript() const { return flags().hasBaseScript(); }
    233 
    234  bool hasBytecode() const {
    235    MOZ_ASSERT(!isIncomplete());
    236    return hasBaseScript() && baseScript()->hasBytecode();
    237  }
    238 
    239  bool isGhost() const { return flags().isGhost(); }
    240 
    241  // Arrow functions store their lexical new.target in the first extended slot.
    242  bool isArrow() const { return flags().isArrow(); }
    243  // Every class-constructor is also a method.
    244  bool isMethod() const { return flags().isMethod(); }
    245  bool isClassConstructor() const { return flags().isClassConstructor(); }
    246 
    247  bool isGetter() const { return flags().isGetter(); }
    248  bool isSetter() const { return flags().isSetter(); }
    249 
    250  bool isAccessorWithLazyName() const {
    251    return flags().isAccessorWithLazyName();
    252  }
    253 
    254  bool allowSuperProperty() const { return flags().allowSuperProperty(); }
    255 
    256  bool hasResolvedLength() const { return flags().hasResolvedLength(); }
    257  bool hasResolvedName() const { return flags().hasResolvedName(); }
    258 
    259  bool isSelfHostedOrIntrinsic() const {
    260    return flags().isSelfHostedOrIntrinsic();
    261  }
    262  bool isSelfHostedBuiltin() const { return flags().isSelfHostedBuiltin(); }
    263 
    264  bool isIntrinsic() const { return flags().isIntrinsic(); }
    265 
    266  bool hasJitScript() const {
    267    if (!hasBaseScript()) {
    268      return false;
    269    }
    270 
    271    return baseScript()->hasJitScript();
    272  }
    273 
    274  /* Compound attributes: */
    275  bool isBuiltin() const { return isBuiltinNative() || isSelfHostedBuiltin(); }
    276 
    277  bool isNamedLambda() const {
    278    return flags().isNamedLambda(maybePartialDisplayAtom() != nullptr);
    279  }
    280 
    281  bool hasLexicalThis() const { return isArrow(); }
    282 
    283  bool isBuiltinFunctionConstructor();
    284  bool needsPrototypeProperty();
    285 
    286  // Returns true if this function must have a non-configurable .prototype data
    287  // property. This is used to ensure looking up .prototype elsewhere will have
    288  // no side-effects.
    289  bool hasNonConfigurablePrototypeDataProperty();
    290 
    291  // Returns true if |new Fun()| should not allocate a new object caller-side
    292  // but pass the uninitialized-lexical MagicValue and rely on the callee to
    293  // construct its own |this| object.
    294  bool constructorNeedsUninitializedThis() const {
    295    MOZ_ASSERT(isConstructor());
    296    MOZ_ASSERT(isInterpreted());
    297    return isDerivedClassConstructor();
    298  }
    299 
    300  /* Returns the strictness of this function, which must be interpreted. */
    301  bool strict() const { return baseScript()->strict(); }
    302 
    303  void setFlags(FunctionFlags flags) { setFlags(flags.toRaw()); }
    304  void setFlags(uint16_t flags) {
    305    uint32_t flagsAndArgCount = flagsAndArgCountRaw();
    306    flagsAndArgCount &= ~FlagsMask;
    307    flagsAndArgCount |= flags;
    308    setReservedSlotPrivateUint32Unbarriered(FlagsAndArgCountSlot,
    309                                            flagsAndArgCount);
    310  }
    311 
    312  // Make the function constructible.
    313  void setIsConstructor() { setFlags(flags().setIsConstructor()); }
    314 
    315  // Can be called multiple times by the parser.
    316  void setArgCount(uint16_t nargs) {
    317    uint32_t flagsAndArgCount = flagsAndArgCountRaw();
    318    flagsAndArgCount &= ~ArgCountMask;
    319    flagsAndArgCount |= nargs << ArgCountShift;
    320    setReservedSlotPrivateUint32Unbarriered(FlagsAndArgCountSlot,
    321                                            flagsAndArgCount);
    322  }
    323 
    324  void setIsSelfHostedBuiltin() { setFlags(flags().setIsSelfHostedBuiltin()); }
    325  void setIsIntrinsic() { setFlags(flags().setIsIntrinsic()); }
    326 
    327  void setResolvedLength() { setFlags(flags().setResolvedLength()); }
    328  void setResolvedName() { setFlags(flags().setResolvedName()); }
    329 
    330  static inline bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
    331                                         uint16_t* length);
    332 
    333  // Returns the function's unresolved name.
    334  // Returns an empty string if the function doesn't have name.
    335  // Returns nullptr when OOM happens.
    336  inline JSAtom* getUnresolvedName(JSContext* cx);
    337 
    338  // Returns the function's unresolved name.
    339  // Returns an empty string if the function doesn't have name.
    340  inline JSAtom* infallibleGetUnresolvedName(JSContext* cx);
    341 
    342  // Returns the name of an accessor function with lazy name.
    343  JSAtom* getAccessorNameForLazy(JSContext* cx);
    344 
    345  // Returns the function's name expclitly specified as syntax, or
    346  // passed when creating a native function.
    347  //
    348  // Returns true and *name!=nullptr if the function has an explicit name.
    349  // Returns true and *name==nullptr if the function doesn't have an explicit
    350  // name.
    351  // Returns false if OOM happens.
    352  bool getExplicitName(JSContext* cx, JS::MutableHandle<JSAtom*> name);
    353 
    354  // Almost same as getExplicitName.
    355  //
    356  // Returns non-nullptr if the function has an explicit name.
    357  // Returns nullptr if the function doesn't have an explicit name.
    358  //
    359  // If this function has lazy name, this returns partial name, such as the
    360  // function name without "get " or "set " prefix.
    361  JSAtom* maybePartialExplicitName() const {
    362    return (hasInferredName() || hasGuessedAtom()) ? nullptr : rawAtom();
    363  }
    364 
    365  // Same as maybePartialExplicitName, except for asserting this function
    366  // doesn't have lazy name.
    367  //
    368  // This can be used e.g. when this function is known to be scripted.
    369  JSAtom* fullExplicitName() const {
    370    MOZ_ASSERT(!isAccessorWithLazyName());
    371    return (hasInferredName() || hasGuessedAtom()) ? nullptr : rawAtom();
    372  }
    373 
    374  JSAtom* fullExplicitOrInferredName() const {
    375    MOZ_ASSERT(!isAccessorWithLazyName());
    376    return hasGuessedAtom() ? nullptr : rawAtom();
    377  }
    378 
    379  void initAtom(JSAtom* atom) {
    380    MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
    381    MOZ_ASSERT(getFixedSlot(AtomSlot).isUndefined());
    382    if (atom) {
    383      initFixedSlot(AtomSlot, JS::StringValue(atom));
    384    }
    385  }
    386 
    387  void setAtom(JSAtom* atom) {
    388    MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
    389    setFixedSlot(AtomSlot, atom ? JS::StringValue(atom) : JS::UndefinedValue());
    390  }
    391 
    392  // Returns the function's name which can be used for informative purpose.
    393  //
    394  // Returns true and *name!=nullptr if the function has a name.
    395  // Returns true and *name==nullptr if the function doesn't have a name.
    396  // Returns false if OOM happens.
    397  bool getDisplayAtom(JSContext* cx, JS::MutableHandle<JSAtom*> name);
    398 
    399  // Almost same as getDisplayAtom.
    400  //
    401  // Returns non-nullptr if the function has a name.
    402  // Returns nullptr if the function doesn't have a name.
    403  //
    404  // If this function has lazy name, this returns partial name, such as the
    405  // function name without "get " or "set " prefix.
    406  JSAtom* maybePartialDisplayAtom() const { return rawAtom(); }
    407 
    408  // Same as maybePartialDisplayAtom, except for asserting this function
    409  // doesn't have lazy name.
    410  //
    411  // This can be used e.g. when this function is known to be scripted.
    412  JSAtom* fullDisplayAtom() const {
    413    MOZ_ASSERT(!isAccessorWithLazyName());
    414    return rawAtom();
    415  }
    416 
    417  JSAtom* rawAtom() const {
    418    JS::Value value = getFixedSlot(AtomSlot);
    419    return value.isUndefined() ? nullptr : &value.toString()->asAtom();
    420  }
    421 
    422  void setInferredName(JSAtom* atom) {
    423    MOZ_ASSERT(!rawAtom());
    424    MOZ_ASSERT(atom);
    425    MOZ_ASSERT(!hasGuessedAtom());
    426    setAtom(atom);
    427    setFlags(flags().setInferredName());
    428  }
    429  JSAtom* inferredName() const {
    430    MOZ_ASSERT(hasInferredName());
    431    MOZ_ASSERT(rawAtom());
    432    return rawAtom();
    433  }
    434 
    435  void setGuessedAtom(JSAtom* atom) {
    436    MOZ_ASSERT(!rawAtom());
    437    MOZ_ASSERT(atom);
    438    MOZ_ASSERT(!hasInferredName());
    439    MOZ_ASSERT(!hasGuessedAtom());
    440    setAtom(atom);
    441    setFlags(flags().setGuessedAtom());
    442  }
    443 
    444  /* uint16_t representation bounds number of call object dynamic slots. */
    445  enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
    446 
    447  /*
    448   * For an interpreted function, accessors for the initial scope object of
    449   * activations (stack frames) of the function.
    450   */
    451  JSObject* environment() const {
    452    MOZ_ASSERT(isInterpreted());
    453    return getFixedSlot(NativeFuncOrInterpretedEnvSlot).toObjectOrNull();
    454  }
    455 
    456  void initEnvironment(JSObject* obj) {
    457    MOZ_ASSERT(isInterpreted());
    458    initFixedSlot(NativeFuncOrInterpretedEnvSlot, JS::ObjectOrNullValue(obj));
    459  }
    460 
    461 public:
    462  static constexpr size_t offsetOfFlagsAndArgCount() {
    463    return getFixedSlotOffset(FlagsAndArgCountSlot);
    464  }
    465  static size_t offsetOfEnvironment() { return offsetOfNativeOrEnv(); }
    466  static size_t offsetOfAtom() { return getFixedSlotOffset(AtomSlot); }
    467 
    468  static bool delazifyLazilyInterpretedFunction(JSContext* cx,
    469                                                js::HandleFunction fun);
    470  static bool delazifySelfHostedLazyFunction(JSContext* cx,
    471                                             js::HandleFunction fun);
    472  void maybeRelazify(JSRuntime* rt);
    473 
    474  // Function Scripts
    475  //
    476  // Interpreted functions have either a BaseScript or a SelfHostedLazyScript. A
    477  // BaseScript may either be lazy or non-lazy (hasBytecode()). Methods may
    478  // return a JSScript* if underlying BaseScript is known to have bytecode.
    479  //
    480  // There are several methods to get the script of an interpreted function:
    481  //
    482  // - For all interpreted functions, getOrCreateScript() will get the
    483  //   JSScript, delazifying the function if necessary. This is the safest to
    484  //   use, but has extra checks, requires a cx and may trigger a GC.
    485  //
    486  // - For functions known to have a JSScript, nonLazyScript() will get it.
    487 
    488  static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
    489    MOZ_ASSERT(fun->isInterpreted());
    490    MOZ_ASSERT(cx);
    491 
    492    if (fun->hasSelfHostedLazyScript()) {
    493      if (!delazifySelfHostedLazyFunction(cx, fun)) {
    494        return nullptr;
    495      }
    496      return fun->nonLazyScript();
    497    }
    498 
    499    MOZ_ASSERT(fun->hasBaseScript());
    500 
    501    if (!fun->baseScript()->hasBytecode()) {
    502      if (!delazifyLazilyInterpretedFunction(cx, fun)) {
    503        return nullptr;
    504      }
    505    }
    506    return fun->nonLazyScript();
    507  }
    508 
    509  // If this is a scripted function, returns its canonical function (the
    510  // original function allocated by the frontend). Note that lazy self-hosted
    511  // builtins don't have a lazy script so in that case we also return nullptr.
    512  JSFunction* maybeCanonicalFunction() const {
    513    if (hasBaseScript()) {
    514      return baseScript()->function();
    515    }
    516    return nullptr;
    517  }
    518 
    519 private:
    520  void* nativeJitInfoOrInterpretedScript() const {
    521    return getFixedSlot(NativeJitInfoOrInterpretedScriptSlot).toPrivate();
    522  }
    523  void setNativeJitInfoOrInterpretedScript(void* ptr) {
    524    // This always stores a PrivateValue and so doesn't require a barrier.
    525    setReservedSlotPrivateUnbarriered(NativeJitInfoOrInterpretedScriptSlot,
    526                                      ptr);
    527  }
    528 
    529 public:
    530  // The default state of a JSFunction that is not ready for execution. If
    531  // observed outside initialization, this is the result of failure during
    532  // bytecode compilation.
    533  //
    534  // A BaseScript is fully initialized before u.script.s.script_ is initialized
    535  // with a reference to it.
    536  bool isIncomplete() const {
    537    return isInterpreted() && !nativeJitInfoOrInterpretedScript();
    538  }
    539 
    540  JSScript* nonLazyScript() const {
    541    MOZ_ASSERT(hasBytecode());
    542    return static_cast<JSScript*>(baseScript());
    543  }
    544 
    545  js::SelfHostedLazyScript* selfHostedLazyScript() const {
    546    MOZ_ASSERT(hasSelfHostedLazyScript());
    547    return static_cast<js::SelfHostedLazyScript*>(
    548        nativeJitInfoOrInterpretedScript());
    549  }
    550 
    551  // Access fields defined on both lazy and non-lazy scripts.
    552  js::BaseScript* baseScript() const {
    553    MOZ_ASSERT(hasBaseScript());
    554    return static_cast<JSScript*>(nativeJitInfoOrInterpretedScript());
    555  }
    556 
    557  static inline bool getLength(JSContext* cx, js::HandleFunction fun,
    558                               uint16_t* length);
    559 
    560  js::Scope* enclosingScope() const { return baseScript()->enclosingScope(); }
    561 
    562  void setEnclosingLazyScript(js::BaseScript* enclosingScript) {
    563    baseScript()->setEnclosingScript(enclosingScript);
    564  }
    565 
    566  js::GeneratorKind generatorKind() const {
    567    if (hasBaseScript()) {
    568      return baseScript()->generatorKind();
    569    }
    570    if (hasSelfHostedLazyScript()) {
    571      return clonedSelfHostedGeneratorKind();
    572    }
    573    return js::GeneratorKind::NotGenerator;
    574  }
    575 
    576  js::GeneratorKind clonedSelfHostedGeneratorKind() const;
    577 
    578  bool isGenerator() const {
    579    return generatorKind() == js::GeneratorKind::Generator;
    580  }
    581 
    582  js::FunctionAsyncKind asyncKind() const {
    583    if (hasBaseScript()) {
    584      return baseScript()->asyncKind();
    585    }
    586    return js::FunctionAsyncKind::SyncFunction;
    587  }
    588 
    589  bool isAsync() const {
    590    return asyncKind() == js::FunctionAsyncKind::AsyncFunction;
    591  }
    592 
    593  bool isGeneratorOrAsync() const { return isGenerator() || isAsync(); }
    594 
    595  void initScript(js::BaseScript* script) {
    596    MOZ_ASSERT_IF(script, realm() == script->realm());
    597    MOZ_ASSERT(isInterpreted());
    598    MOZ_ASSERT_IF(hasBaseScript(),
    599                  !baseScript());  // No write barrier required.
    600    setNativeJitInfoOrInterpretedScript(script);
    601  }
    602 
    603  void initSelfHostedLazyScript(js::SelfHostedLazyScript* lazy) {
    604    MOZ_ASSERT(isSelfHostedBuiltin());
    605    MOZ_ASSERT(isInterpreted());
    606    if (hasBaseScript()) {
    607      js::gc::PreWriteBarrier(baseScript());
    608    }
    609    FunctionFlags f = flags();
    610    f.clearBaseScript();
    611    f.setSelfHostedLazy();
    612    setFlags(f);
    613    setNativeJitInfoOrInterpretedScript(lazy);
    614    MOZ_ASSERT(hasSelfHostedLazyScript());
    615  }
    616 
    617  void clearSelfHostedLazyScript() {
    618    MOZ_ASSERT(isSelfHostedBuiltin());
    619    MOZ_ASSERT(isInterpreted());
    620    MOZ_ASSERT(!hasBaseScript());  // No write barrier required.
    621    FunctionFlags f = flags();
    622    f.clearSelfHostedLazy();
    623    f.setBaseScript();
    624    setFlags(f);
    625    setNativeJitInfoOrInterpretedScript(nullptr);
    626    MOZ_ASSERT(isIncomplete());
    627  }
    628 
    629  JSNative native() const {
    630    MOZ_ASSERT(isNativeFun());
    631    return nativeUnchecked();
    632  }
    633  JSNative nativeUnchecked() const {
    634    // Can be called by Ion off-main thread.
    635    JS::Value value = getFixedSlot(NativeFuncOrInterpretedEnvSlot);
    636    return reinterpret_cast<JSNative>(value.toPrivate());
    637  }
    638 
    639  JSNative maybeNative() const { return isInterpreted() ? nullptr : native(); }
    640 
    641  void initNative(js::Native native, const JSJitInfo* jitInfo) {
    642    MOZ_ASSERT(isNativeFun());
    643    MOZ_ASSERT_IF(jitInfo, isBuiltinNative());
    644    MOZ_ASSERT(native);
    645    initFixedSlot(NativeFuncOrInterpretedEnvSlot,
    646                  JS::PrivateValue(reinterpret_cast<void*>(native)));
    647    setNativeJitInfoOrInterpretedScript(const_cast<JSJitInfo*>(jitInfo));
    648  }
    649  bool hasJitInfo() const {
    650    return flags().canHaveJitInfo() && jitInfoUnchecked();
    651  }
    652  const JSJitInfo* jitInfo() const {
    653    MOZ_ASSERT(hasJitInfo());
    654    return jitInfoUnchecked();
    655  }
    656  const JSJitInfo* jitInfoUnchecked() const {
    657    // Can be called by Ion off-main thread.
    658    return static_cast<const JSJitInfo*>(nativeJitInfoOrInterpretedScript());
    659  }
    660  void setJitInfo(const JSJitInfo* data) {
    661    MOZ_ASSERT(isBuiltinNative());
    662    MOZ_ASSERT(data);
    663    setNativeJitInfoOrInterpretedScript(const_cast<JSJitInfo*>(data));
    664  }
    665 
    666  void setTrampolineNativeJitEntry(void** entry) {
    667    MOZ_ASSERT(*entry);
    668    MOZ_ASSERT(isBuiltinNative());
    669    MOZ_ASSERT(!hasJitEntry());
    670    MOZ_ASSERT(!hasJitInfo(), "shouldn't clobber JSJitInfo");
    671    setFlags(flags().setNativeJitEntry());
    672    setNativeJitInfoOrInterpretedScript(entry);
    673    MOZ_ASSERT(isNativeWithJitEntry());
    674  }
    675  void** nativeJitEntry() const {
    676    MOZ_ASSERT(isNativeWithJitEntry());
    677    return static_cast<void**>(nativeJitInfoOrInterpretedScript());
    678  }
    679 
    680  // wasm functions are always natives and either:
    681  //  - store a function-index in u.n.extra and can only be called through the
    682  //    fun->native() entry point from C++.
    683  //  - store a jit-entry code pointer in u.n.extra and can be called by jit
    684  //    code directly. C++ callers can still use the fun->native() entry point
    685  //    (computing the function index from the jit-entry point).
    686  void initWasm(uint32_t funcIndex, js::wasm::Instance* instance,
    687                const js::wasm::SuperTypeVector* superTypeVector,
    688                void* uncheckedCallEntry);
    689  void initWasmWithJitEntry(void** entry, js::wasm::Instance* instance,
    690                            const js::wasm::SuperTypeVector* superTypeVector,
    691                            void* uncheckedCallEntry);
    692 
    693  void** wasmJitEntry() const {
    694    MOZ_ASSERT(isWasmWithJitEntry());
    695    return nativeJitEntry();
    696  }
    697  inline js::wasm::Instance& wasmInstance() const;
    698  uint32_t wasmFuncIndex() const;
    699  void* wasmUncheckedCallEntry() const;
    700  void* wasmCheckedCallEntry() const;
    701  inline js::wasm::SuperTypeVector& wasmSuperTypeVector() const;
    702  inline const js::wasm::TypeDef* wasmTypeDef() const;
    703 
    704  bool isDerivedClassConstructor() const;
    705  bool isSyntheticFunction() const;
    706 
    707  static unsigned offsetOfNativeOrEnv() {
    708    return getFixedSlotOffset(NativeFuncOrInterpretedEnvSlot);
    709  }
    710  static unsigned offsetOfJitInfoOrScript() {
    711    return getFixedSlotOffset(NativeJitInfoOrInterpretedScriptSlot);
    712  }
    713 
    714  inline void trace(JSTracer* trc);
    715 
    716 public:
    717  inline bool isExtended() const {
    718    bool extended = flags().isExtended();
    719    MOZ_ASSERT_IF(isTenured(),
    720                  extended == (asTenured().getAllocKind() ==
    721                               js::gc::AllocKind::FUNCTION_EXTENDED));
    722    return extended;
    723  }
    724 
    725  /*
    726   * Accessors for data stored in extended functions. Use setExtendedSlot if the
    727   * function has already been initialized. Otherwise use initExtendedSlot.
    728   */
    729  inline void initExtendedSlot(uint32_t slot, const js::Value& val);
    730  inline void setExtendedSlot(uint32_t slot, const js::Value& val);
    731  inline const js::Value& getExtendedSlot(uint32_t slot) const;
    732 
    733  /* GC support. */
    734  js::gc::AllocKind getAllocKind() const {
    735    static_assert(
    736        js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
    737        "extended/non-extended AllocKinds have to be different "
    738        "for getAllocKind() to have a reason to exist");
    739 
    740    js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
    741    if (isExtended()) {
    742      kind = js::gc::AllocKind::FUNCTION_EXTENDED;
    743    }
    744    MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
    745    return kind;
    746  }
    747 
    748  // If we're constructing with this function, choose an appropriate
    749  // allocKind.
    750  static bool getAllocKindForThis(JSContext* cx, js::HandleFunction func,
    751                                  js::gc::AllocKind& allocKind);
    752 
    753 #if defined(DEBUG) || defined(JS_JITSPEW)
    754  void dumpOwnFields(js::JSONPrinter& json) const;
    755  void dumpOwnStringContent(js::GenericPrinter& out) const;
    756 #endif
    757 };
    758 
    759 static_assert(sizeof(JSFunction) == sizeof(JS::shadow::Function),
    760              "shadow interface must match actual interface");
    761 
    762 static_assert(unsigned(JSFunction::FlagsAndArgCountSlot) ==
    763              unsigned(JS::shadow::Function::FlagsAndArgCountSlot));
    764 static_assert(unsigned(JSFunction::NativeFuncOrInterpretedEnvSlot) ==
    765              unsigned(JS::shadow::Function::NativeFuncOrInterpretedEnvSlot));
    766 static_assert(
    767    unsigned(JSFunction::NativeJitInfoOrInterpretedScriptSlot) ==
    768    unsigned(JS::shadow::Function::NativeJitInfoOrInterpretedScriptSlot));
    769 static_assert(unsigned(JSFunction::AtomSlot) ==
    770              unsigned(JS::shadow::Function::AtomSlot));
    771 
    772 namespace js {
    773 
    774 extern JSString* fun_toStringHelper(JSContext* cx, HandleObject obj,
    775                                    bool isToSource);
    776 
    777 extern bool Function(JSContext* cx, unsigned argc, Value* vp);
    778 
    779 extern bool Generator(JSContext* cx, unsigned argc, Value* vp);
    780 
    781 extern bool AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
    782 
    783 extern bool AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
    784 
    785 // If enclosingEnv is null, the function will have a null environment()
    786 // (yes, null, not the global lexical environment).  In all cases, the global
    787 // will be used as the terminating environment.
    788 
    789 extern JSFunction* NewFunctionWithProto(
    790    JSContext* cx, JSNative native, unsigned nargs, FunctionFlags flags,
    791    HandleObject enclosingEnv, Handle<JSAtom*> atom, HandleObject proto,
    792    gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
    793    NewObjectKind newKind = GenericObject);
    794 
    795 // Allocate a new function backed by a JSNative.  Note that by default this
    796 // creates a tenured object.
    797 inline JSFunction* NewNativeFunction(
    798    JSContext* cx, JSNative native, unsigned nargs, Handle<JSAtom*> atom,
    799    gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
    800    NewObjectKind newKind = TenuredObject,
    801    FunctionFlags flags = FunctionFlags::NATIVE_FUN) {
    802  MOZ_ASSERT(native);
    803  return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
    804                              allocKind, newKind);
    805 }
    806 
    807 // Allocate a new constructor backed by a JSNative.  Note that by default this
    808 // creates a tenured object.
    809 inline JSFunction* NewNativeConstructor(
    810    JSContext* cx, JSNative native, unsigned nargs, Handle<JSAtom*> atom,
    811    gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
    812    NewObjectKind newKind = TenuredObject,
    813    FunctionFlags flags = FunctionFlags::NATIVE_CTOR) {
    814  MOZ_ASSERT(native);
    815  MOZ_ASSERT(flags.isNativeConstructor());
    816  return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
    817                              allocKind, newKind);
    818 }
    819 
    820 // Determine which [[Prototype]] to use when creating a new function using the
    821 // requested generator and async kind.
    822 //
    823 // This sets `proto` to `nullptr` for non-generator, synchronous functions to
    824 // mean "the builtin %FunctionPrototype% in the current realm", the common case.
    825 //
    826 // We could set it to `cx->global()->getOrCreateFunctionPrototype()`, but
    827 // nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
    828 extern bool GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
    829                                 js::FunctionAsyncKind asyncKind,
    830                                 js::MutableHandleObject proto);
    831 
    832 extern JSAtom* IdToFunctionName(
    833    JSContext* cx, HandleId id,
    834    FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
    835 
    836 extern bool SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name,
    837                            FunctionPrefixKind prefixKind);
    838 
    839 extern JSFunction* DefineFunction(
    840    JSContext* cx, HandleObject obj, HandleId id, JSNative native,
    841    unsigned nargs, unsigned flags,
    842    gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
    843 
    844 extern bool fun_toString(JSContext* cx, unsigned argc, Value* vp);
    845 
    846 extern void ThrowTypeErrorBehavior(JSContext* cx);
    847 
    848 /*
    849 * Function extended with reserved slots for use by various kinds of functions.
    850 * Most functions do not have these extensions, but enough do that efficient
    851 * storage is required (no malloc'ed reserved slots).
    852 */
    853 class FunctionExtended : public JSFunction {
    854 public:
    855  enum {
    856    FirstExtendedSlot = JSFunction::SlotCount,
    857    SecondExtendedSlot,
    858    ThirdExtendedSlot,
    859 
    860    SlotCount
    861  };
    862 
    863  static const uint32_t NUM_EXTENDED_SLOTS = 3;
    864 
    865  static const uint32_t METHOD_HOMEOBJECT_SLOT = 0;
    866 
    867  // wasm/asm.js exported functions store a code pointer to their direct entry
    868  // point (see CodeRange::funcUncheckedCallEntry()) to support the call_ref
    869  // instruction.
    870  static const uint32_t WASM_FUNC_UNCHECKED_ENTRY_SLOT = 0;
    871 
    872  // wasm/asm.js exported functions store the wasm::Instance pointer of their
    873  // instance.
    874  static const uint32_t WASM_INSTANCE_SLOT = 1;
    875 
    876  // wasm/asm.js exported functions store a pointer to their
    877  // wasm::SuperTypeVector for downcasting.
    878  static const uint32_t WASM_STV_SLOT = 2;
    879 
    880  // asm.js module functions store their WasmModuleObject in the first slot.
    881  static const uint32_t ASMJS_MODULE_SLOT = 0;
    882 
    883  // Async module callback handlers store their ModuleObject in the first slot.
    884  static const uint32_t MODULE_SLOT = 0;
    885 
    886  static inline size_t offsetOfExtendedSlot(uint32_t which) {
    887    MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
    888    return getFixedSlotOffset(FirstExtendedSlot + which);
    889  }
    890  static inline size_t offsetOfMethodHomeObjectSlot() {
    891    return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
    892  }
    893  static inline size_t offsetOfWasmSTV() {
    894    return offsetOfExtendedSlot(WASM_STV_SLOT);
    895  }
    896 
    897 private:
    898  friend class JSFunction;
    899 };
    900 
    901 extern JSFunction* CloneFunctionReuseScript(JSContext* cx, HandleFunction fun,
    902                                            HandleObject enclosingEnv,
    903                                            HandleObject proto,
    904                                            gc::Heap heap = gc::Heap::Default,
    905                                            gc::AllocSite* site = nullptr);
    906 
    907 extern JSFunction* CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun);
    908 
    909 }  // namespace js
    910 
    911 template <>
    912 inline bool JSObject::is<JSFunction>() const {
    913  return getClass()->isJSFunction();
    914 }
    915 
    916 inline void JSFunction::initExtendedSlot(uint32_t which, const js::Value& val) {
    917  MOZ_ASSERT(isExtended());
    918  MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS);
    919  MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
    920  initFixedSlot(js::FunctionExtended::FirstExtendedSlot + which, val);
    921 }
    922 
    923 inline void JSFunction::setExtendedSlot(uint32_t which, const js::Value& val) {
    924  MOZ_ASSERT(isExtended());
    925  MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS);
    926  MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
    927  setFixedSlot(js::FunctionExtended::FirstExtendedSlot + which, val);
    928 }
    929 
    930 inline const js::Value& JSFunction::getExtendedSlot(uint32_t which) const {
    931  MOZ_ASSERT(isExtended());
    932  MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS);
    933  return getFixedSlot(js::FunctionExtended::FirstExtendedSlot + which);
    934 }
    935 
    936 inline js::wasm::Instance& JSFunction::wasmInstance() const {
    937  MOZ_ASSERT(isWasm() || isAsmJSNative());
    938  MOZ_ASSERT(
    939      !getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).isUndefined());
    940  return *static_cast<js::wasm::Instance*>(
    941      getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).toPrivate());
    942 }
    943 
    944 inline js::wasm::SuperTypeVector& JSFunction::wasmSuperTypeVector() const {
    945  MOZ_ASSERT(isWasm());
    946  MOZ_ASSERT(
    947      !getExtendedSlot(js::FunctionExtended::WASM_STV_SLOT).isUndefined());
    948  return *static_cast<js::wasm::SuperTypeVector*>(
    949      getExtendedSlot(js::FunctionExtended::WASM_STV_SLOT).toPrivate());
    950 }
    951 
    952 inline const js::wasm::TypeDef* JSFunction::wasmTypeDef() const {
    953  MOZ_ASSERT(isWasm());
    954  return wasmSuperTypeVector().typeDef();
    955 }
    956 
    957 namespace js {
    958 
    959 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);
    960 
    961 /*
    962 * Report an error that call.thisv is not compatible with the specified class,
    963 * assuming that the method (clasp->name).prototype.<name of callee function>
    964 * is what was called.
    965 */
    966 extern void ReportIncompatibleMethod(JSContext* cx, const CallArgs& args,
    967                                     const JSClass* clasp);
    968 
    969 /*
    970 * Report an error that call.thisv is not an acceptable this for the callee
    971 * function.
    972 */
    973 extern void ReportIncompatible(JSContext* cx, const CallArgs& args);
    974 
    975 extern bool fun_apply(JSContext* cx, unsigned argc, Value* vp);
    976 
    977 extern bool fun_call(JSContext* cx, unsigned argc, Value* vp);
    978 
    979 } /* namespace js */
    980 
    981 #ifdef DEBUG
    982 namespace JS {
    983 namespace detail {
    984 
    985 JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev);
    986 
    987 }  // namespace detail
    988 }  // namespace JS
    989 #endif
    990 
    991 #endif /* vm_JSFunction_h */