tor-browser

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

FunctionFlags.h (16262B)


      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_FunctionFlags_h
      8 #define vm_FunctionFlags_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_ASSERT_IF
     11 #include "mozilla/Attributes.h"  // MOZ_IMPLICIT
     12 
     13 #include <stdint.h>  // uint8_t, uint16_t
     14 
     15 #include "jstypes.h"  // JS_PUBLIC_API
     16 
     17 class JS_PUBLIC_API JSAtom;
     18 
     19 namespace js {
     20 
     21 class FunctionFlags {
     22 public:
     23  // Syntactic characteristics of a function.
     24  enum FunctionKind : uint8_t {
     25    // Regular function that doesn't match any of the other kinds.
     26    //
     27    // This kind is used by the following scipted functions:
     28    //   * FunctionDeclaration
     29    //   * FunctionExpression
     30    //   * Function created from Function() call or its variants
     31    //
     32    // Also all native functions excluding AsmJS and Wasm use this kind.
     33    NormalFunction = 0,
     34 
     35    // ES6 '(args) => body' syntax.
     36    // This kind is used only by scripted function.
     37    Arrow,
     38 
     39    // ES6 MethodDefinition syntax.
     40    // This kind is used only by scripted function.
     41    Method,
     42 
     43    // Class constructor syntax, or default constructor.
     44    // This kind is used only by scripted function and default constructor.
     45    //
     46    // WARNING: This is independent from Flags::CONSTRUCTOR.
     47    ClassConstructor,
     48 
     49    // Getter and setter syntax in objects or classes, or
     50    // native getter and setter created from JSPropertySpec.
     51    // This kind is used both by scripted functions and native functions.
     52    Getter,
     53    Setter,
     54 
     55    // An asm.js module or exported function.
     56    //
     57    // This kind is used only by scripted function, and used only when the
     58    // asm.js module is created.
     59    //
     60    // "use asm" directive itself doesn't necessarily imply this kind.
     61    // e.g. arrow function with "use asm" becomes Arrow kind,
     62    //
     63    // See EstablishPreconditions in js/src/wasm/AsmJS.cpp
     64    AsmJS,
     65 
     66    // An exported WebAssembly function.
     67    Wasm,
     68 
     69    FunctionKindLimit
     70  };
     71 
     72  enum Flags : uint16_t {
     73    // FunctionKind enum value.
     74    FUNCTION_KIND_SHIFT = 0,
     75    FUNCTION_KIND_MASK = 0x0007,
     76 
     77    // The AllocKind used was FunctionExtended and extra slots were allocated.
     78    // These slots may be used by the engine or the embedding so care must be
     79    // taken to avoid conflicts.
     80    //
     81    // This flag is used both by scripted functions and native functions.
     82    EXTENDED = 1 << 3,
     83 
     84    // Set if function is a self-hosted builtin or intrinsic. An 'intrinsic'
     85    // here means a native function used inside self-hosted code. In general, a
     86    // self-hosted function should appear to script as though it were a native
     87    // builtin.
     88    SELF_HOSTED = 1 << 4,
     89 
     90    // An interpreted function has or may-have bytecode and an environment. Only
     91    // one of these flags may be used at a time. As a memory optimization, the
     92    // SELFHOSTLAZY flag indicates there is no js::BaseScript at all and we must
     93    // clone from the self-hosted realm in order to get bytecode.
     94    BASESCRIPT = 1 << 5,
     95    SELFHOSTLAZY = 1 << 6,
     96 
     97    // This Native function has a JIT entry which emulates the
     98    // js::BaseScript::jitCodeRaw mechanism. Used for Wasm functions and
     99    // TrampolineNative builtins.
    100    NATIVE_JIT_ENTRY = 1 << 7,
    101 
    102    // Function may be called as a constructor. This corresponds in the spec as
    103    // having a [[Construct]] internal method.
    104    //
    105    // e.g. FunctionDeclaration has this flag, but GeneratorDeclaration doesn't
    106    //      have this flag.
    107    //
    108    // This flag is used both by scripted functions and native functions.
    109    //
    110    // WARNING: This is independent from FunctionKind::ClassConstructor.
    111    CONSTRUCTOR = 1 << 8,
    112 
    113    // Function comes from a FunctionExpression, ArrowFunction, or Function()
    114    // call (not a FunctionDeclaration).
    115    //
    116    // This flag is used only by scripted functions and AsmJS.
    117    LAMBDA = 1 << 9,
    118 
    119    // Function is either getter or setter, with "get " or "set " prefix,
    120    // but JSFunction::AtomSlot contains unprefixed name, and the function name
    121    // is lazily constructed on the first access.
    122    LAZY_ACCESSOR_NAME = 1 << 10,
    123 
    124    // Function had no explicit name, but a name was set by SetFunctionName at
    125    // compile time or SetFunctionName at runtime.
    126    //
    127    // This flag can be used both by scripted functions and native functions.
    128    HAS_INFERRED_NAME = 1 << 11,
    129 
    130    // Function had no explicit name, but a name was guessed for it anyway.
    131    //
    132    // This flag is used only by scripted function.
    133    HAS_GUESSED_ATOM = 1 << 12,
    134 
    135    // The 'length' or 'name property has been resolved. See fun_resolve.
    136    //
    137    // These flags are used both by scripted functions and native functions.
    138    RESOLVED_NAME = 1 << 13,
    139    RESOLVED_LENGTH = 1 << 14,
    140 
    141    // This function is kept only for skipping it over during delazification.
    142    //
    143    // This function is inside arrow function's parameter expression, and
    144    // parsed twice, once before finding "=>" token, and once after finding
    145    // "=>" and rewinding to the beginning of the parameters.
    146    // ScriptStencil is created for both case, and the first one is kept only
    147    // for delazification, to make sure delazification sees the same sequence
    148    // of inner function to skip over.
    149    //
    150    // We call the first one "ghost".
    151    // It should be kept lazy, and shouldn't be exposed to debugger.
    152    //
    153    // This flag is used only by scripted functions.
    154    GHOST_FUNCTION = 1 << 15,
    155 
    156    // Shifted form of FunctionKinds.
    157    NORMAL_KIND = NormalFunction << FUNCTION_KIND_SHIFT,
    158    ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
    159    WASM_KIND = Wasm << FUNCTION_KIND_SHIFT,
    160    ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
    161    METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
    162    CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
    163    GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
    164    SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
    165 
    166    // Derived Flags combinations to use when creating functions.
    167    NATIVE_FUN = NORMAL_KIND,
    168    NATIVE_CTOR = CONSTRUCTOR | NORMAL_KIND,
    169    NATIVE_GETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | GETTER_KIND,
    170    NATIVE_SETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | SETTER_KIND,
    171    ASMJS_CTOR = CONSTRUCTOR | ASMJS_KIND,
    172    ASMJS_LAMBDA_CTOR = CONSTRUCTOR | LAMBDA | ASMJS_KIND,
    173    WASM = WASM_KIND,
    174    INTERPRETED_NORMAL = BASESCRIPT | CONSTRUCTOR | NORMAL_KIND,
    175    INTERPRETED_CLASS_CTOR = BASESCRIPT | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
    176    INTERPRETED_GENERATOR_OR_ASYNC = BASESCRIPT | NORMAL_KIND,
    177    INTERPRETED_LAMBDA = BASESCRIPT | LAMBDA | CONSTRUCTOR | NORMAL_KIND,
    178    INTERPRETED_LAMBDA_ARROW = BASESCRIPT | LAMBDA | ARROW_KIND,
    179    INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = BASESCRIPT | LAMBDA | NORMAL_KIND,
    180    INTERPRETED_GETTER = BASESCRIPT | GETTER_KIND,
    181    INTERPRETED_SETTER = BASESCRIPT | SETTER_KIND,
    182    INTERPRETED_METHOD = BASESCRIPT | METHOD_KIND,
    183 
    184    // Flags that XDR ignores. See also: js::BaseScript::MutableFlags.
    185    MUTABLE_FLAGS = RESOLVED_NAME | RESOLVED_LENGTH,
    186 
    187    // Flags preserved when cloning a function.
    188    STABLE_ACROSS_CLONES =
    189        CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK | GHOST_FUNCTION
    190  };
    191 
    192  uint16_t flags_;
    193 
    194 public:
    195  FunctionFlags() : flags_() {
    196    static_assert(sizeof(FunctionFlags) == sizeof(flags_),
    197                  "No extra members allowed is it'll grow JSFunction");
    198    static_assert(offsetof(FunctionFlags, flags_) == 0,
    199                  "Required for JIT flag access");
    200  }
    201 
    202  explicit FunctionFlags(uint16_t flags) : flags_(flags) {}
    203  MOZ_IMPLICIT FunctionFlags(Flags f) : flags_(f) {}
    204 
    205  static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <=
    206                    FUNCTION_KIND_MASK,
    207                "FunctionKind doesn't fit into flags_");
    208 
    209  uint16_t toRaw() const { return flags_; }
    210 
    211  uint16_t stableAcrossClones() const { return flags_ & STABLE_ACROSS_CLONES; }
    212 
    213  // For flag combinations the type is int.
    214  bool hasFlags(uint16_t flags) const { return flags_ & flags; }
    215  FunctionFlags& setFlags(uint16_t flags) {
    216    flags_ |= flags;
    217    return *this;
    218  }
    219  FunctionFlags& clearFlags(uint16_t flags) {
    220    flags_ &= ~flags;
    221    return *this;
    222  }
    223  FunctionFlags& setFlags(uint16_t flags, bool set) {
    224    if (set) {
    225      setFlags(flags);
    226    } else {
    227      clearFlags(flags);
    228    }
    229    return *this;
    230  }
    231 
    232  FunctionKind kind() const {
    233    return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >>
    234                                     FUNCTION_KIND_SHIFT);
    235  }
    236 
    237 #ifdef DEBUG
    238  void assertFunctionKindIntegrity() {
    239    switch (kind()) {
    240      case FunctionKind::NormalFunction:
    241        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    242        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    243        break;
    244 
    245      case FunctionKind::Arrow:
    246        MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
    247        MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
    248        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    249        MOZ_ASSERT(hasFlags(LAMBDA));
    250        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    251        break;
    252      case FunctionKind::Method:
    253        MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
    254        MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
    255        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    256        MOZ_ASSERT(!hasFlags(LAMBDA));
    257        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    258        break;
    259      case FunctionKind::ClassConstructor:
    260        MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
    261        MOZ_ASSERT(hasFlags(CONSTRUCTOR));
    262        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    263        MOZ_ASSERT(!hasFlags(LAMBDA));
    264        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    265        break;
    266      case FunctionKind::Getter:
    267        MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
    268        MOZ_ASSERT(!hasFlags(LAMBDA));
    269        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    270        break;
    271      case FunctionKind::Setter:
    272        MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
    273        MOZ_ASSERT(!hasFlags(LAMBDA));
    274        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    275        break;
    276 
    277      case FunctionKind::AsmJS:
    278        MOZ_ASSERT(!hasFlags(BASESCRIPT));
    279        MOZ_ASSERT(!hasFlags(SELFHOSTLAZY));
    280        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    281        MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY));
    282        break;
    283      case FunctionKind::Wasm:
    284        MOZ_ASSERT(!hasFlags(BASESCRIPT));
    285        MOZ_ASSERT(!hasFlags(SELFHOSTLAZY));
    286        MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
    287        MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
    288        MOZ_ASSERT(!hasFlags(LAMBDA));
    289        break;
    290      default:
    291        break;
    292    }
    293  }
    294 #endif
    295 
    296  /* A function can be classified as either native (C++) or interpreted (JS): */
    297  bool isInterpreted() const {
    298    return hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY);
    299  }
    300  bool isNativeFun() const { return !isInterpreted(); }
    301 
    302  bool isConstructor() const { return hasFlags(CONSTRUCTOR); }
    303 
    304  bool isNonBuiltinConstructor() const {
    305    // Note: keep this in sync with branchIfNotFunctionIsNonBuiltinCtor in
    306    // MacroAssembler.cpp.
    307    return hasFlags(BASESCRIPT) && hasFlags(CONSTRUCTOR) &&
    308           !hasFlags(SELF_HOSTED);
    309  }
    310 
    311  /* Possible attributes of a native function: */
    312  bool isAsmJSNative() const {
    313    MOZ_ASSERT_IF(kind() == AsmJS, isNativeFun());
    314    return kind() == AsmJS;
    315  }
    316  bool isWasm() const {
    317    MOZ_ASSERT_IF(kind() == Wasm, isNativeFun());
    318    return kind() == Wasm;
    319  }
    320  bool isNativeWithJitEntry() const {
    321    MOZ_ASSERT_IF(hasFlags(NATIVE_JIT_ENTRY), isNativeFun());
    322    return hasFlags(NATIVE_JIT_ENTRY);
    323  }
    324  bool isWasmWithJitEntry() const { return isWasm() && isNativeWithJitEntry(); }
    325  bool isNativeWithoutJitEntry() const {
    326    MOZ_ASSERT_IF(!hasJitEntry(), isNativeFun());
    327    return !hasJitEntry();
    328  }
    329  bool isBuiltinNative() const {
    330    return isNativeFun() && !isAsmJSNative() && !isWasm();
    331  }
    332  bool hasJitEntry() const {
    333    return hasBaseScript() || hasSelfHostedLazyScript() ||
    334           isNativeWithJitEntry();
    335  }
    336 
    337  bool canHaveJitInfo() const {
    338    // A native builtin can have a pointer to either its JitEntry or JSJitInfo,
    339    // but not both.
    340    return isBuiltinNative() && !isNativeWithJitEntry();
    341  }
    342 
    343  /* Possible attributes of an interpreted function: */
    344  bool hasInferredName() const { return hasFlags(HAS_INFERRED_NAME); }
    345  bool hasGuessedAtom() const { return hasFlags(HAS_GUESSED_ATOM); }
    346  bool isLambda() const { return hasFlags(LAMBDA); }
    347 
    348  bool isNamedLambda(bool hasName) const {
    349    return hasName && isLambda() && !hasInferredName() && !hasGuessedAtom();
    350  }
    351 
    352  // These methods determine which of the u.scripted.s union arms are active.
    353  // For live JSFunctions the pointer values will always be non-null, but due
    354  // to partial initialization the GC (and other features that scan the heap
    355  // directly) may still return a null pointer.
    356  bool hasBaseScript() const { return hasFlags(BASESCRIPT); }
    357  bool hasSelfHostedLazyScript() const { return hasFlags(SELFHOSTLAZY); }
    358 
    359  // Arrow functions store their lexical new.target in the first extended slot.
    360  bool isArrow() const { return kind() == Arrow; }
    361  // Every class-constructor is also a method.
    362  bool isMethod() const {
    363    return kind() == Method || kind() == ClassConstructor;
    364  }
    365  bool isClassConstructor() const { return kind() == ClassConstructor; }
    366 
    367  bool isGetter() const { return kind() == Getter; }
    368  bool isSetter() const { return kind() == Setter; }
    369 
    370  bool isAccessorWithLazyName() const { return hasFlags(LAZY_ACCESSOR_NAME); }
    371 
    372  bool allowSuperProperty() const {
    373    return isMethod() || isGetter() || isSetter();
    374  }
    375 
    376  bool hasResolvedLength() const { return hasFlags(RESOLVED_LENGTH); }
    377  bool hasResolvedName() const { return hasFlags(RESOLVED_NAME); }
    378 
    379  bool isSelfHostedOrIntrinsic() const { return hasFlags(SELF_HOSTED); }
    380  bool isSelfHostedBuiltin() const {
    381    return isSelfHostedOrIntrinsic() && !isNativeFun();
    382  }
    383  bool isIntrinsic() const {
    384    return isSelfHostedOrIntrinsic() && isNativeFun();
    385  }
    386 
    387  FunctionFlags& setKind(FunctionKind kind) {
    388    this->flags_ &= ~FUNCTION_KIND_MASK;
    389    this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
    390    return *this;
    391  }
    392 
    393  // Make the function constructible.
    394  FunctionFlags& setIsConstructor() {
    395    MOZ_ASSERT(!isConstructor());
    396    MOZ_ASSERT(isSelfHostedBuiltin());
    397    return setFlags(CONSTRUCTOR);
    398  }
    399 
    400  FunctionFlags& setIsSelfHostedBuiltin() {
    401    MOZ_ASSERT(isInterpreted());
    402    MOZ_ASSERT(!isSelfHostedBuiltin());
    403    setFlags(SELF_HOSTED);
    404    // Self-hosted functions should not be constructable.
    405    return clearFlags(CONSTRUCTOR);
    406  }
    407  FunctionFlags& setIsIntrinsic() {
    408    MOZ_ASSERT(isNativeFun());
    409    MOZ_ASSERT(!isIntrinsic());
    410    return setFlags(SELF_HOSTED);
    411  }
    412 
    413  FunctionFlags& setResolvedLength() { return setFlags(RESOLVED_LENGTH); }
    414  FunctionFlags& setResolvedName() { return setFlags(RESOLVED_NAME); }
    415 
    416  FunctionFlags& setInferredName() { return setFlags(HAS_INFERRED_NAME); }
    417 
    418  FunctionFlags& setGuessedAtom() { return setFlags(HAS_GUESSED_ATOM); }
    419 
    420  FunctionFlags& setSelfHostedLazy() { return setFlags(SELFHOSTLAZY); }
    421  FunctionFlags& clearSelfHostedLazy() { return clearFlags(SELFHOSTLAZY); }
    422  FunctionFlags& setBaseScript() { return setFlags(BASESCRIPT); }
    423  FunctionFlags& clearBaseScript() { return clearFlags(BASESCRIPT); }
    424 
    425  FunctionFlags& clearLazyAccessorName() {
    426    return clearFlags(LAZY_ACCESSOR_NAME);
    427  }
    428 
    429  FunctionFlags& setNativeJitEntry() { return setFlags(NATIVE_JIT_ENTRY); }
    430 
    431  bool isExtended() const { return hasFlags(EXTENDED); }
    432  FunctionFlags& setIsExtended() { return setFlags(EXTENDED); }
    433 
    434  bool isNativeConstructor() const { return hasFlags(NATIVE_CTOR); }
    435 
    436  FunctionFlags& setIsGhost() { return setFlags(GHOST_FUNCTION); }
    437  bool isGhost() const { return hasFlags(GHOST_FUNCTION); }
    438 
    439  static constexpr uint16_t HasJitEntryFlags() {
    440    return BASESCRIPT | SELFHOSTLAZY | NATIVE_JIT_ENTRY;
    441  }
    442 
    443  static FunctionFlags clearMutableflags(FunctionFlags flags) {
    444    return FunctionFlags(flags.toRaw() & ~FunctionFlags::MUTABLE_FLAGS);
    445  }
    446 };
    447 
    448 } /* namespace js */
    449 
    450 #endif /* vm_FunctionFlags_h */