tor-browser

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

RealmFuses.h (15853B)


      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_RealmFuses_h
      8 #define vm_RealmFuses_h
      9 
     10 #include "vm/GuardFuse.h"
     11 #include "vm/InvalidatingFuse.h"
     12 
     13 namespace js {
     14 
     15 class NativeObject;
     16 struct RealmFuses;
     17 
     18 // [SMDOC] RealmFuses:
     19 //
     20 // Realm fuses are fuses associated with a specific realm. As a result,
     21 // popFuse for realmFuses has another argument, the set of realmFuses related to
     22 // the fuse being popped. This is used to find any dependent fuses in the realm
     23 // (rather than using the context).
     24 class RealmFuse : public GuardFuse {
     25 public:
     26  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) { popFuse(cx); }
     27 
     28 protected:
     29  virtual void popFuse(JSContext* cx) override { GuardFuse::popFuse(cx); }
     30 };
     31 
     32 class InvalidatingRealmFuse : public InvalidatingFuse {
     33 public:
     34  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses);
     35  virtual bool addFuseDependency(JSContext* cx,
     36                                 const jit::IonScriptKey& ionScript) override;
     37 
     38 protected:
     39  virtual void popFuse(JSContext* cx) override {
     40    InvalidatingFuse::popFuse(cx);
     41  }
     42 };
     43 
     44 // Fuse guarding against changes to `Array.prototype[@@iterator]` and
     45 // `%ArrayIteratorPrototype%` that affect the iterator protocol for packed
     46 // arrays.
     47 //
     48 // Popped when one of the following fuses is popped:
     49 // - ArrayPrototypeIteratorFuse (for `Array.prototype[@@iterator]`)
     50 // - OptimizeArrayIteratorPrototypeFuse (for `%ArrayIteratorPrototype%`)
     51 struct OptimizeGetIteratorFuse final : public InvalidatingRealmFuse {
     52  virtual const char* name() override { return "OptimizeGetIteratorFuse"; }
     53  virtual bool checkInvariant(JSContext* cx) override;
     54  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
     55 };
     56 
     57 struct PopsOptimizedGetIteratorFuse : public RealmFuse {
     58  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
     59 };
     60 
     61 // Fuse guarding against changes to `%ArrayIteratorPrototype%` (and its
     62 // prototype chain) that affect the iterator protocol.
     63 //
     64 // Popped when one of the following fuses is popped:
     65 // - ArrayPrototypeIteratorNextFuse
     66 // - ArrayIteratorPrototypeHasNoReturnProperty
     67 // - ArrayIteratorPrototypeHasIteratorProto
     68 // - IteratorPrototypeHasNoReturnProperty
     69 // - IteratorPrototypeHasObjectProto
     70 // - ObjectPrototypeHasNoReturnProperty
     71 struct OptimizeArrayIteratorPrototypeFuse final
     72    : public PopsOptimizedGetIteratorFuse {
     73  virtual const char* name() override {
     74    return "OptimizeArrayIteratorPrototypeFuse";
     75  }
     76  virtual bool checkInvariant(JSContext* cx) override;
     77 };
     78 
     79 struct PopsOptimizedArrayIteratorPrototypeFuse : public RealmFuse {
     80  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
     81 };
     82 
     83 struct ArrayPrototypeIteratorFuse final : public PopsOptimizedGetIteratorFuse {
     84  virtual const char* name() override { return "ArrayPrototypeIteratorFuse"; }
     85  virtual bool checkInvariant(JSContext* cx) override;
     86 };
     87 
     88 struct ArrayPrototypeIteratorNextFuse final
     89    : public PopsOptimizedArrayIteratorPrototypeFuse {
     90  virtual const char* name() override {
     91    return "ArrayPrototypeIteratorNextFuse";
     92  }
     93  virtual bool checkInvariant(JSContext* cx) override;
     94 };
     95 
     96 // This fuse covers ArrayIteratorPrototype not having a return property;
     97 // however the fuse doesn't pop if a prototype acquires the return property.
     98 struct ArrayIteratorPrototypeHasNoReturnProperty final
     99    : public PopsOptimizedArrayIteratorPrototypeFuse {
    100  virtual const char* name() override {
    101    return "ArrayIteratorPrototypeHasNoReturnProperty";
    102  }
    103  virtual bool checkInvariant(JSContext* cx) override;
    104 };
    105 
    106 // This fuse covers IteratorPrototype not having a return property;
    107 // however the fuse doesn't pop if a prototype acquires the return property.
    108 struct IteratorPrototypeHasNoReturnProperty final
    109    : public PopsOptimizedArrayIteratorPrototypeFuse {
    110  virtual const char* name() override {
    111    return "IteratorPrototypeHasNoReturnProperty";
    112  }
    113  virtual bool checkInvariant(JSContext* cx) override;
    114 };
    115 
    116 struct ArrayIteratorPrototypeHasIteratorProto final
    117    : public PopsOptimizedArrayIteratorPrototypeFuse {
    118  virtual const char* name() override {
    119    return "ArrayIteratorPrototypeHasIteratorProto";
    120  }
    121  virtual bool checkInvariant(JSContext* cx) override;
    122 };
    123 
    124 struct IteratorPrototypeHasObjectProto final
    125    : public PopsOptimizedArrayIteratorPrototypeFuse {
    126  virtual const char* name() override {
    127    return "IteratorPrototypeHasObjectProto";
    128  }
    129  virtual bool checkInvariant(JSContext* cx) override;
    130 };
    131 
    132 struct ObjectPrototypeHasNoReturnProperty final
    133    : public PopsOptimizedArrayIteratorPrototypeFuse {
    134  virtual const char* name() override {
    135    return "ObjectPrototypeHasNoReturnProperty";
    136  }
    137  virtual bool checkInvariant(JSContext* cx) override;
    138 };
    139 
    140 // Fuse used to optimize @@species lookups for arrays. If this fuse is intact,
    141 // the following invariants must hold:
    142 //
    143 // - The builtin `Array.prototype` object has a `constructor` property that's
    144 //   the builtin `Array` constructor.
    145 // - This `Array` constructor has a `Symbol.species` property that's the
    146 //   original accessor.
    147 struct OptimizeArraySpeciesFuse final : public InvalidatingRealmFuse {
    148  virtual const char* name() override { return "OptimizeArraySpeciesFuse"; }
    149  virtual bool checkInvariant(JSContext* cx) override;
    150  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
    151 };
    152 
    153 // Fuse used to optimize @@species lookups for ArrayBuffers. If this fuse is
    154 // intact, the following invariants must hold:
    155 //
    156 // - The builtin `ArrayBuffer.prototype` object has a `constructor` property
    157 //   that's the builtin `ArrayBuffer` constructor.
    158 // - This `ArrayBuffer` constructor has a `Symbol.species` property that's the
    159 //   original accessor.
    160 struct OptimizeArrayBufferSpeciesFuse final : public RealmFuse {
    161  virtual const char* name() override {
    162    return "OptimizeArrayBufferSpeciesFuse";
    163  }
    164  virtual bool checkInvariant(JSContext* cx) override;
    165 };
    166 
    167 // Fuse used to optimize @@species lookups for SharedArrayBuffers. If this fuse
    168 // is intact, the following invariants must hold:
    169 //
    170 // - The builtin `SharedArrayBuffer.prototype` object has a `constructor`
    171 //   property that's the builtin `SharedArrayBuffer` constructor.
    172 // - This `SharedArrayBuffer` constructor has a `Symbol.species` property that's
    173 //   the original accessor.
    174 struct OptimizeSharedArrayBufferSpeciesFuse final : public RealmFuse {
    175  virtual const char* name() override {
    176    return "OptimizeSharedArrayBufferSpeciesFuse";
    177  }
    178  virtual bool checkInvariant(JSContext* cx) override;
    179 };
    180 
    181 // Fuse used to optimize @@species lookups for TypedArrays. If this fuse is
    182 // intact, the following invariants must hold:
    183 //
    184 // - The builtin `%TypedArray%.prototype` object has a `constructor` property
    185 //   that's the builtin `%TypedArray%` constructor.
    186 // - This `%TypedArray%` constructor has a `Symbol.species` property that's the
    187 //   original accessor.
    188 // - The builtin `<TypedArray>.prototype` object has a `constructor` property
    189 //   that's the builtin `<TypedArray>` constructor and the prototype of
    190 //   `<TypedArray>.prototype` is %TypedArray%.prototype.
    191 //   Where `<TypedArray>` is all concrete built-in TypedArray types:
    192 //   - Int8Array
    193 //   - Uint8Array
    194 //   - Uint8ClampedArray
    195 //   - Int16Array
    196 //   - Uint16Array
    197 //   - Int32Array
    198 //   - Uint32Array
    199 //   - BigInt64Array
    200 //   - BigUint64Array
    201 //   - Float16Array
    202 //   - Float32Array
    203 //   - Float64Array
    204 struct OptimizeTypedArraySpeciesFuse final : public InvalidatingRealmFuse {
    205  virtual const char* name() override {
    206    return "OptimizeTypedArraySpeciesFuse";
    207  }
    208  virtual bool checkInvariant(JSContext* cx) override;
    209 };
    210 
    211 // Fuse used to optimize various property lookups for promises. If this fuse is
    212 // intact, the following invariants must hold:
    213 //
    214 // - The builtin `Promise.prototype` object has unchanged `constructor` and
    215 //   `then` properties.
    216 // - The builtin `Promise` constructor has unchanged `Symbol.species` and
    217 //   `resolve` properties.
    218 struct OptimizePromiseLookupFuse final : public RealmFuse {
    219  virtual const char* name() override { return "OptimizePromiseLookupFuse"; }
    220  virtual bool checkInvariant(JSContext* cx) override;
    221  virtual void popFuse(JSContext* cx, RealmFuses& realmFuses) override;
    222 };
    223 
    224 // Fuse used to guard against changes to various properties on RegExp.prototype.
    225 //
    226 // If this fuse is intact, RegExp.prototype must have the following original
    227 // getter properties:
    228 // - .flags ($RegExpFlagsGetter)
    229 // - .global (regexp_global)
    230 // - .hasIndices (regexp_hasIndices)
    231 // - .ignoreCase (regexp_ignoreCase)
    232 // - .multiline (regexp_multiline)
    233 // - .sticky (regexp_sticky)
    234 // - .unicode (regexp_unicode)
    235 // - .unicodeSets (regexp_unicodeSets)
    236 // - .dotAll (regexp_dotAll)
    237 //
    238 // And the following unchanged data properties:
    239 // - .exec (RegExp_prototype_Exec)
    240 // - [@@match] (RegExpMatch)
    241 // - [@@matchAll] (RegExpMatchAll)
    242 // - [@@replace] (RegExpReplace)
    243 // - [@@search] (RegExpSearch)
    244 // - [@@split] (RegExpSplit)
    245 struct OptimizeRegExpPrototypeFuse final : public InvalidatingRealmFuse {
    246  virtual const char* name() override { return "OptimizeRegExpPrototypeFuse"; }
    247  virtual bool checkInvariant(JSContext* cx) override;
    248 };
    249 
    250 // Guard used to optimize iterating over Map objects. If this fuse is intact,
    251 // the following invariants must hold:
    252 //
    253 // - The builtin `Map.prototype` object has a `Symbol.iterator` property that's
    254 //   the original `%Map.prototype.entries%` function.
    255 // - The builtin `%MapIteratorPrototype%` object has a `next` property that's
    256 //   the original `MapIteratorNext` self-hosted function.
    257 //
    258 // Note: because this doesn't guard against `return` properties on the iterator
    259 // prototype, this should only be used in places where we don't have to call
    260 // `IteratorClose`.
    261 struct OptimizeMapObjectIteratorFuse final : public RealmFuse {
    262  virtual const char* name() override {
    263    return "OptimizeMapObjectIteratorFuse";
    264  }
    265  virtual bool checkInvariant(JSContext* cx) override;
    266 };
    267 
    268 // Guard used to optimize iterating over Set objects. If this fuse is intact,
    269 // the following invariants must hold:
    270 //
    271 // - The builtin `Set.prototype` object has a `Symbol.iterator` property that's
    272 //   the original `%Set.prototype.values%` function.
    273 // - The builtin `%SetIteratorPrototype%` object has a `next` property that's
    274 //   the original `SetIteratorNext` self-hosted function.
    275 //
    276 // Note: because this doesn't guard against `return` properties on the iterator
    277 // prototype, this should only be used in places where we don't have to call
    278 // `IteratorClose`.
    279 struct OptimizeSetObjectIteratorFuse final : public RealmFuse {
    280  virtual const char* name() override {
    281    return "OptimizeSetObjectIteratorFuse";
    282  }
    283  virtual bool checkInvariant(JSContext* cx) override;
    284 };
    285 
    286 // This fuse is popped when the `Map.prototype.set` property is mutated.
    287 struct OptimizeMapPrototypeSetFuse final : public RealmFuse {
    288  virtual const char* name() override { return "OptimizeMapPrototypeSetFuse"; }
    289  virtual bool checkInvariant(JSContext* cx) override;
    290 };
    291 
    292 // This fuse is popped when the `Set.prototype.add` property is mutated.
    293 struct OptimizeSetPrototypeAddFuse final : public RealmFuse {
    294  virtual const char* name() override { return "OptimizeSetPrototypeAddFuse"; }
    295  virtual bool checkInvariant(JSContext* cx) override;
    296 };
    297 
    298 // This fuse is popped when the `WeakMap.prototype.set` property is mutated.
    299 struct OptimizeWeakMapPrototypeSetFuse final : public RealmFuse {
    300  virtual const char* name() override {
    301    return "OptimizeWeakMapPrototypeSetFuse";
    302  }
    303  virtual bool checkInvariant(JSContext* cx) override;
    304 };
    305 
    306 // This fuse is popped when the `WeakSet.prototype.add` property is mutated.
    307 struct OptimizeWeakSetPrototypeAddFuse final : public RealmFuse {
    308  virtual const char* name() override {
    309    return "OptimizeWeakSetPrototypeAddFuse";
    310  }
    311  virtual bool checkInvariant(JSContext* cx) override;
    312 };
    313 
    314 #define FOR_EACH_REALM_FUSE(FUSE)                                              \
    315  FUSE(OptimizeGetIteratorFuse, optimizeGetIteratorFuse)                       \
    316  FUSE(OptimizeArrayIteratorPrototypeFuse, optimizeArrayIteratorPrototypeFuse) \
    317  FUSE(ArrayPrototypeIteratorFuse, arrayPrototypeIteratorFuse)                 \
    318  FUSE(ArrayPrototypeIteratorNextFuse, arrayPrototypeIteratorNextFuse)         \
    319  FUSE(ArrayIteratorPrototypeHasNoReturnProperty,                              \
    320       arrayIteratorPrototypeHasNoReturnProperty)                              \
    321  FUSE(IteratorPrototypeHasNoReturnProperty,                                   \
    322       iteratorPrototypeHasNoReturnProperty)                                   \
    323  FUSE(ArrayIteratorPrototypeHasIteratorProto,                                 \
    324       arrayIteratorPrototypeHasIteratorProto)                                 \
    325  FUSE(IteratorPrototypeHasObjectProto, iteratorPrototypeHasObjectProto)       \
    326  FUSE(ObjectPrototypeHasNoReturnProperty, objectPrototypeHasNoReturnProperty) \
    327  FUSE(OptimizeArraySpeciesFuse, optimizeArraySpeciesFuse)                     \
    328  FUSE(OptimizeArrayBufferSpeciesFuse, optimizeArrayBufferSpeciesFuse)         \
    329  FUSE(OptimizeSharedArrayBufferSpeciesFuse,                                   \
    330       optimizeSharedArrayBufferSpeciesFuse)                                   \
    331  FUSE(OptimizeTypedArraySpeciesFuse, optimizeTypedArraySpeciesFuse)           \
    332  FUSE(OptimizePromiseLookupFuse, optimizePromiseLookupFuse)                   \
    333  FUSE(OptimizeRegExpPrototypeFuse, optimizeRegExpPrototypeFuse)               \
    334  FUSE(OptimizeMapObjectIteratorFuse, optimizeMapObjectIteratorFuse)           \
    335  FUSE(OptimizeSetObjectIteratorFuse, optimizeSetObjectIteratorFuse)           \
    336  FUSE(OptimizeMapPrototypeSetFuse, optimizeMapPrototypeSetFuse)               \
    337  FUSE(OptimizeSetPrototypeAddFuse, optimizeSetPrototypeAddFuse)               \
    338  FUSE(OptimizeWeakMapPrototypeSetFuse, optimizeWeakMapPrototypeSetFuse)       \
    339  FUSE(OptimizeWeakSetPrototypeAddFuse, optimizeWeakSetPrototypeAddFuse)
    340 
    341 struct RealmFuses {
    342  RealmFuses() = default;
    343 
    344 #define FUSE(Name, LowerName) Name LowerName{};
    345  FOR_EACH_REALM_FUSE(FUSE)
    346 #undef FUSE
    347 
    348  void assertInvariants(JSContext* cx) {
    349 // Generate the invariant checking calls.
    350 #define FUSE(Name, LowerName) LowerName.assertInvariant(cx);
    351    FOR_EACH_REALM_FUSE(FUSE)
    352 #undef FUSE
    353  }
    354 
    355  // Code Generation Code:
    356  enum class FuseIndex : uint8_t {
    357  // Generate Fuse Indexes
    358 #define FUSE(Name, LowerName) Name,
    359    FOR_EACH_REALM_FUSE(FUSE)
    360 #undef FUSE
    361        LastFuseIndex
    362  };
    363 
    364  GuardFuse* getFuseByIndex(FuseIndex index) {
    365    switch (index) {
    366      // Return fuses.
    367 #define FUSE(Name, LowerName) \
    368  case FuseIndex::Name:       \
    369    return &this->LowerName;
    370      FOR_EACH_REALM_FUSE(FUSE)
    371 #undef FUSE
    372      default:
    373        break;
    374    }
    375    MOZ_CRASH("Fuse Not Found");
    376  }
    377 
    378  DependentIonScriptGroup fuseDependencies;
    379 
    380  static int32_t fuseOffsets[];
    381  static const char* fuseNames[];
    382 
    383  static int32_t offsetOfFuseWordRelativeToRealm(FuseIndex index);
    384  static const char* getFuseName(FuseIndex index);
    385 
    386 #ifdef DEBUG
    387  static bool isInvalidatingFuse(FuseIndex index) {
    388    switch (index) {
    389 #  define FUSE(Name, LowerName)                                      \
    390    case FuseIndex::Name:                                            \
    391      static_assert(std::is_base_of_v<RealmFuse, Name> ||            \
    392                    std::is_base_of_v<InvalidatingRealmFuse, Name>); \
    393      return std::is_base_of_v<InvalidatingRealmFuse, Name>;
    394      FOR_EACH_REALM_FUSE(FUSE)
    395 #  undef FUSE
    396      default:
    397        break;
    398    }
    399    MOZ_CRASH("Fuse Not Found");
    400  }
    401 #endif
    402 };
    403 
    404 }  // namespace js
    405 
    406 #endif