tor-browser

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

PropertySpec.h (17245B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /* Property descriptors and flags. */
      7 
      8 #ifndef js_PropertySpec_h
      9 #define js_PropertySpec_h
     10 
     11 #include "mozilla/Assertions.h"  // MOZ_ASSERT{,_IF}
     12 
     13 #include <stddef.h>     // size_t
     14 #include <stdint.h>     // uint8_t, uint16_t, int32_t, uint32_t, uintptr_t
     15 #include <type_traits>  // std::enable_if
     16 
     17 #include "jstypes.h"  // JS_PUBLIC_API
     18 
     19 #include "js/CallArgs.h"            // JSNative
     20 #include "js/PropertyDescriptor.h"  // JSPROP_*
     21 #include "js/RootingAPI.h"          // JS::MutableHandle
     22 #include "js/Symbol.h"              // JS::SymbolCode, PropertySpecNameIsSymbol
     23 #include "js/Value.h"               // JS::Value
     24 
     25 struct JS_PUBLIC_API JSContext;
     26 class JSJitInfo;
     27 
     28 /**
     29 * Wrapper to relace JSNative for JSPropertySpecs and JSFunctionSpecs. This will
     30 * allow us to pass one JSJitInfo per function with the property/function spec,
     31 * without additional field overhead.
     32 */
     33 struct JSNativeWrapper {
     34  JSNative op = nullptr;
     35  const JSJitInfo* info = nullptr;
     36 
     37  JSNativeWrapper() = default;
     38 
     39  JSNativeWrapper(const JSNativeWrapper& other) = default;
     40 
     41  constexpr JSNativeWrapper(JSNative op, const JSJitInfo* info)
     42      : op(op), info(info) {}
     43 };
     44 
     45 /**
     46 * Description of a property. JS_DefineProperties and JS_InitClass take arrays
     47 * of these and define many properties at once. JS_PSG, JS_PSGS and JS_PS_END
     48 * are helper macros for defining such arrays.
     49 */
     50 struct JSPropertySpec {
     51  struct SelfHostedWrapper {
     52    // The same type as JSNativeWrapper's first field, so that the access in
     53    // JSPropertySpec::checkAccessorsAreSelfHosted become valid.
     54    JSNative unused = nullptr;
     55 
     56    const char* funname;
     57 
     58    SelfHostedWrapper() = delete;
     59 
     60    explicit constexpr SelfHostedWrapper(const char* funname)
     61        : funname(funname) {}
     62  };
     63 
     64  struct ValueWrapper {
     65    enum class Type : uint8_t { String, Int32, Double };
     66    Type type;
     67    union {
     68      const char* string;
     69      int32_t int32;
     70      double double_;
     71    };
     72 
     73   private:
     74    ValueWrapper() = delete;
     75 
     76    explicit constexpr ValueWrapper(int32_t n) : type(Type::Int32), int32(n) {}
     77 
     78    explicit constexpr ValueWrapper(const char* s)
     79        : type(Type::String), string(s) {}
     80 
     81    explicit constexpr ValueWrapper(double d)
     82        : type(Type::Double), double_(d) {}
     83 
     84   public:
     85    ValueWrapper(const ValueWrapper& other) = default;
     86 
     87    static constexpr ValueWrapper int32Value(int32_t n) {
     88      return ValueWrapper(n);
     89    }
     90 
     91    static constexpr ValueWrapper stringValue(const char* s) {
     92      return ValueWrapper(s);
     93    }
     94 
     95    static constexpr ValueWrapper doubleValue(double d) {
     96      return ValueWrapper(d);
     97    }
     98  };
     99 
    100  union Accessor {
    101    JSNativeWrapper native;
    102    SelfHostedWrapper selfHosted;
    103 
    104   private:
    105    Accessor() = delete;
    106 
    107    constexpr Accessor(JSNative op, const JSJitInfo* info) : native(op, info) {}
    108 
    109    explicit constexpr Accessor(const char* funname) : selfHosted(funname) {}
    110 
    111   public:
    112    Accessor(const Accessor& other) = default;
    113 
    114    static constexpr Accessor nativeAccessor(JSNative op,
    115                                             const JSJitInfo* info = nullptr) {
    116      return Accessor(op, info);
    117    }
    118 
    119    static constexpr Accessor selfHostedAccessor(const char* funname) {
    120      return Accessor(funname);
    121    }
    122 
    123    static constexpr Accessor noAccessor() {
    124      return Accessor(nullptr, nullptr);
    125    }
    126  };
    127 
    128  union AccessorsOrValue {
    129    struct Accessors {
    130      Accessor getter;
    131      Accessor setter;
    132 
    133      constexpr Accessors(Accessor getter, Accessor setter)
    134          : getter(getter), setter(setter) {}
    135    } accessors;
    136    ValueWrapper value;
    137 
    138   private:
    139    AccessorsOrValue() = delete;
    140 
    141    constexpr AccessorsOrValue(Accessor getter, Accessor setter)
    142        : accessors(getter, setter) {}
    143 
    144    explicit constexpr AccessorsOrValue(ValueWrapper value) : value(value) {}
    145 
    146   public:
    147    AccessorsOrValue(const AccessorsOrValue& other) = default;
    148 
    149    static constexpr AccessorsOrValue fromAccessors(Accessor getter,
    150                                                    Accessor setter) {
    151      return AccessorsOrValue(getter, setter);
    152    }
    153 
    154    static constexpr AccessorsOrValue fromValue(ValueWrapper value) {
    155      return AccessorsOrValue(value);
    156    }
    157  };
    158 
    159  union Name {
    160   private:
    161    const char* string_;
    162    uintptr_t symbol_;
    163 
    164   public:
    165    Name() = delete;
    166 
    167    explicit constexpr Name(const char* str) : string_(str) {}
    168    explicit constexpr Name(JS::SymbolCode symbol)
    169        : symbol_(uint32_t(symbol) + 1) {}
    170 
    171    explicit operator bool() const { return !!symbol_; }
    172 
    173    bool isSymbol() const { return JS::PropertySpecNameIsSymbol(symbol_); }
    174    JS::SymbolCode symbol() const {
    175      MOZ_ASSERT(isSymbol());
    176      return JS::SymbolCode(symbol_ - 1);
    177    }
    178 
    179    bool isString() const { return !isSymbol(); }
    180    const char* string() const {
    181      MOZ_ASSERT(isString());
    182      return string_;
    183    }
    184  };
    185 
    186  Name name;
    187 
    188 private:
    189  // JSPROP_* property attributes as defined in PropertyDescriptor.h.
    190  uint8_t attributes_;
    191 
    192  // Whether AccessorsOrValue below stores a value, JSNative accessors, or
    193  // self-hosted accessors.
    194  enum class Kind : uint8_t { Value, SelfHostedAccessor, NativeAccessor };
    195  Kind kind_;
    196 
    197 public:
    198  AccessorsOrValue u;
    199 
    200 private:
    201  JSPropertySpec() = delete;
    202 
    203  constexpr JSPropertySpec(const char* name, uint8_t attributes, Kind kind,
    204                           AccessorsOrValue u)
    205      : name(name), attributes_(attributes), kind_(kind), u(u) {}
    206  constexpr JSPropertySpec(JS::SymbolCode name, uint8_t attributes, Kind kind,
    207                           AccessorsOrValue u)
    208      : name(name), attributes_(attributes), kind_(kind), u(u) {}
    209 
    210 public:
    211  JSPropertySpec(const JSPropertySpec& other) = default;
    212 
    213  static constexpr JSPropertySpec nativeAccessors(
    214      const char* name, uint8_t attributes, JSNative getter,
    215      const JSJitInfo* getterInfo, JSNative setter = nullptr,
    216      const JSJitInfo* setterInfo = nullptr) {
    217    return JSPropertySpec(
    218        name, attributes, Kind::NativeAccessor,
    219        AccessorsOrValue::fromAccessors(
    220            JSPropertySpec::Accessor::nativeAccessor(getter, getterInfo),
    221            JSPropertySpec::Accessor::nativeAccessor(setter, setterInfo)));
    222  }
    223 
    224  static constexpr JSPropertySpec nativeAccessors(
    225      JS::SymbolCode name, uint8_t attributes, JSNative getter,
    226      const JSJitInfo* getterInfo, JSNative setter = nullptr,
    227      const JSJitInfo* setterInfo = nullptr) {
    228    return JSPropertySpec(
    229        name, attributes, Kind::NativeAccessor,
    230        AccessorsOrValue::fromAccessors(
    231            JSPropertySpec::Accessor::nativeAccessor(getter, getterInfo),
    232            JSPropertySpec::Accessor::nativeAccessor(setter, setterInfo)));
    233  }
    234 
    235  static constexpr JSPropertySpec selfHostedAccessors(
    236      const char* name, uint8_t attributes, const char* getterName,
    237      const char* setterName = nullptr) {
    238    return JSPropertySpec(
    239        name, attributes, Kind::SelfHostedAccessor,
    240        AccessorsOrValue::fromAccessors(
    241            JSPropertySpec::Accessor::selfHostedAccessor(getterName),
    242            setterName
    243                ? JSPropertySpec::Accessor::selfHostedAccessor(setterName)
    244                : JSPropertySpec::Accessor::noAccessor()));
    245  }
    246 
    247  static constexpr JSPropertySpec selfHostedAccessors(
    248      JS::SymbolCode name, uint8_t attributes, const char* getterName,
    249      const char* setterName = nullptr) {
    250    return JSPropertySpec(
    251        name, attributes, Kind::SelfHostedAccessor,
    252        AccessorsOrValue::fromAccessors(
    253            JSPropertySpec::Accessor::selfHostedAccessor(getterName),
    254            setterName
    255                ? JSPropertySpec::Accessor::selfHostedAccessor(setterName)
    256                : JSPropertySpec::Accessor::noAccessor()));
    257  }
    258 
    259  static constexpr JSPropertySpec int32Value(const char* name,
    260                                             uint8_t attributes, int32_t n) {
    261    return JSPropertySpec(name, attributes, Kind::Value,
    262                          AccessorsOrValue::fromValue(
    263                              JSPropertySpec::ValueWrapper::int32Value(n)));
    264  }
    265 
    266  static constexpr JSPropertySpec int32Value(JS::SymbolCode name,
    267                                             uint8_t attributes, int32_t n) {
    268    return JSPropertySpec(name, attributes, Kind::Value,
    269                          AccessorsOrValue::fromValue(
    270                              JSPropertySpec::ValueWrapper::int32Value(n)));
    271  }
    272 
    273  static constexpr JSPropertySpec stringValue(const char* name,
    274                                              uint8_t attributes,
    275                                              const char* s) {
    276    return JSPropertySpec(name, attributes, Kind::Value,
    277                          AccessorsOrValue::fromValue(
    278                              JSPropertySpec::ValueWrapper::stringValue(s)));
    279  }
    280 
    281  static constexpr JSPropertySpec stringValue(JS::SymbolCode name,
    282                                              uint8_t attributes,
    283                                              const char* s) {
    284    return JSPropertySpec(name, attributes, Kind::Value,
    285                          AccessorsOrValue::fromValue(
    286                              JSPropertySpec::ValueWrapper::stringValue(s)));
    287  }
    288 
    289  static constexpr JSPropertySpec doubleValue(const char* name,
    290                                              uint8_t attributes, double d) {
    291    return JSPropertySpec(name, attributes, Kind::Value,
    292                          AccessorsOrValue::fromValue(
    293                              JSPropertySpec::ValueWrapper::doubleValue(d)));
    294  }
    295 
    296  static constexpr JSPropertySpec sentinel() {
    297    return JSPropertySpec(nullptr, 0, Kind::NativeAccessor,
    298                          AccessorsOrValue::fromAccessors(
    299                              JSPropertySpec::Accessor::noAccessor(),
    300                              JSPropertySpec::Accessor::noAccessor()));
    301  }
    302 
    303  unsigned attributes() const { return attributes_; }
    304 
    305  bool isAccessor() const {
    306    return (kind_ == Kind::NativeAccessor || kind_ == Kind::SelfHostedAccessor);
    307  }
    308 
    309  JS_PUBLIC_API bool getValue(JSContext* cx,
    310                              JS::MutableHandle<JS::Value> value) const;
    311 
    312  bool isSelfHosted() const {
    313    MOZ_ASSERT(isAccessor());
    314 #ifdef DEBUG
    315    // Verify that our accessors match our Kind.
    316    if (kind_ == Kind::SelfHostedAccessor) {
    317      checkAccessorsAreSelfHosted();
    318    } else {
    319      checkAccessorsAreNative();
    320    }
    321 #endif
    322    return kind_ == Kind::SelfHostedAccessor;
    323  }
    324 
    325  static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper),
    326                "JSPropertySpec::getter/setter must be compact");
    327  static_assert(offsetof(SelfHostedWrapper, unused) ==
    328                        offsetof(JSNativeWrapper, op) &&
    329                    offsetof(SelfHostedWrapper, funname) ==
    330                        offsetof(JSNativeWrapper, info),
    331                "checkAccessorsAreNative below require that "
    332                "SelfHostedWrapper::funname overlay "
    333                "JSNativeWrapper::info and "
    334                "SelfHostedWrapper::unused overlay "
    335                "JSNativeWrapper::op");
    336 
    337 private:
    338  void checkAccessorsAreNative() const {
    339    // We may have a getter or a setter or both.  And whichever ones we have
    340    // should not have a SelfHostedWrapper for the accessor.
    341    MOZ_ASSERT_IF(u.accessors.getter.native.info, u.accessors.getter.native.op);
    342    MOZ_ASSERT_IF(u.accessors.setter.native.info, u.accessors.setter.native.op);
    343  }
    344 
    345  void checkAccessorsAreSelfHosted() const {
    346    MOZ_ASSERT(!u.accessors.getter.selfHosted.unused);
    347    MOZ_ASSERT(!u.accessors.setter.selfHosted.unused);
    348  }
    349 };
    350 
    351 // There can be many JSPropertySpec instances so verify the size is what we
    352 // expect:
    353 //
    354 // - Name (1 word)
    355 // - attributes_ + isAccessor_ (1 word)
    356 // - AccessorsOrValue (4 words, native + JSJitInfo for both getter and setter)
    357 static_assert(sizeof(JSPropertySpec) == 6 * sizeof(uintptr_t));
    358 
    359 template <unsigned Attributes>
    360 constexpr uint8_t CheckAccessorAttrs() {
    361  static_assert((Attributes & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT)) == 0,
    362                "Unexpected flag (not JSPROP_ENUMERATE or JSPROP_PERMANENT)");
    363  return uint8_t(Attributes);
    364 }
    365 
    366 #define JS_PSG(name, getter, attributes)                                  \
    367  JSPropertySpec::nativeAccessors(name, CheckAccessorAttrs<attributes>(), \
    368                                  getter, nullptr)
    369 #define JS_INLINABLE_PSG(name, getter, attributes, native)                \
    370  JSPropertySpec::nativeAccessors(name, CheckAccessorAttrs<attributes>(), \
    371                                  getter, &js::jit::JitInfo_##native)
    372 #define JS_PSGS(name, getter, setter, attributes)                         \
    373  JSPropertySpec::nativeAccessors(name, CheckAccessorAttrs<attributes>(), \
    374                                  getter, nullptr, setter, nullptr)
    375 #define JS_SYM_GET(symbol, getter, attributes)                              \
    376  JSPropertySpec::nativeAccessors(::JS::SymbolCode::symbol,                 \
    377                                  CheckAccessorAttrs<attributes>(), getter, \
    378                                  nullptr)
    379 #define JS_SYM_GETSET(symbol, getter, setter, attributes)                   \
    380  JSPropertySpec::nativeAccessors(::JS::SymbolCode::symbol,                 \
    381                                  CheckAccessorAttrs<attributes>(), getter, \
    382                                  nullptr, setter, nullptr)
    383 #define JS_SELF_HOSTED_GET(name, getterName, attributes)                      \
    384  JSPropertySpec::selfHostedAccessors(name, CheckAccessorAttrs<attributes>(), \
    385                                      getterName)
    386 #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, attributes)       \
    387  JSPropertySpec::selfHostedAccessors(name, CheckAccessorAttrs<attributes>(), \
    388                                      getterName, setterName)
    389 #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, attributes) \
    390  JSPropertySpec::selfHostedAccessors(                         \
    391      ::JS::SymbolCode::symbol, CheckAccessorAttrs<attributes>(), getterName)
    392 #define JS_STRING_PS(name, string, attributes) \
    393  JSPropertySpec::stringValue(name, attributes, string)
    394 #define JS_STRING_SYM_PS(symbol, string, attributes) \
    395  JSPropertySpec::stringValue(::JS::SymbolCode::symbol, attributes, string)
    396 #define JS_INT32_PS(name, value, attributes) \
    397  JSPropertySpec::int32Value(name, attributes, value)
    398 #define JS_DOUBLE_PS(name, value, attributes) \
    399  JSPropertySpec::doubleValue(name, attributes, value)
    400 #define JS_PS_END JSPropertySpec::sentinel()
    401 
    402 /**
    403 * To define a native function, set call to a JSNativeWrapper. To define a
    404 * self-hosted function, set selfHostedName to the name of a function
    405 * compiled during JSRuntime::initSelfHosting.
    406 */
    407 struct JSFunctionSpec {
    408  using Name = JSPropertySpec::Name;
    409 
    410  Name name;
    411  JSNativeWrapper call;
    412  uint16_t nargs;
    413  uint16_t flags;
    414  const char* selfHostedName;
    415 
    416  // JSPROP_* property attributes as defined in PropertyDescriptor.h
    417  unsigned attributes() const { return flags; }
    418 };
    419 
    420 /*
    421 * Terminating sentinel initializer to put at the end of a JSFunctionSpec array
    422 * that's passed to JS_DefineFunctions or JS_InitClass.
    423 */
    424 #define JS_FS_END JS_FN(nullptr, nullptr, 0, 0)
    425 
    426 /*
    427 * Initializer macros for a JSFunctionSpec array element.
    428 *
    429 * - JS_FNINFO allows the simple adding of JSJitInfos.
    430 * - JS_SELF_HOSTED_FN declares a self-hosted function.
    431 * - JS_INLINABLE_FN allows specifying an InlinableNative enum value for natives
    432 *   inlined or specialized by the JIT.
    433 * - JS_TRAMPOLINE_FN allows specifying a TrampolineNative enum value for
    434 *   natives that have a JitEntry trampoline.
    435 * - JS_FNSPEC has slots for all the fields.
    436 *
    437 * The _SYM variants allow defining a function with a symbol key rather than a
    438 * string key. For example, use JS_SYM_FN(iterator, ...) to define an
    439 * @@iterator method.
    440 */
    441 #define JS_FN(name, call, nargs, flags) \
    442  JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
    443 #define JS_INLINABLE_FN(name, call, nargs, flags, native) \
    444  JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr)
    445 #define JS_TRAMPOLINE_FN(name, call, nargs, flags, native) \
    446  JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr)
    447 #define JS_SYM_FN(symbol, call, nargs, flags) \
    448  JS_SYM_FNSPEC(symbol, call, nullptr, nargs, flags, nullptr)
    449 #define JS_FNINFO(name, call, info, nargs, flags) \
    450  JS_FNSPEC(name, call, info, nargs, flags, nullptr)
    451 #define JS_SELF_HOSTED_FN(name, selfHostedName, nargs, flags) \
    452  JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
    453 #define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
    454  JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
    455 #define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
    456  JS_FNSPEC(::JS::SymbolCode::symbol, call, info, nargs, flags, selfHostedName)
    457 #define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \
    458  {JSFunctionSpec::Name(name), {call, info}, nargs, flags, selfHostedName}
    459 
    460 #endif  // js_PropertySpec_h