tor-browser

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

TypePolicy.h (20321B)


      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 jit_TypePolicy_h
      8 #define jit_TypePolicy_h
      9 
     10 #include "jit/IonTypes.h"
     11 #include "js/ScalarType.h"  // js::Scalar::Type
     12 
     13 namespace js {
     14 namespace jit {
     15 
     16 class MInstruction;
     17 class MDefinition;
     18 class TempAllocator;
     19 
     20 extern MDefinition* BoxAt(TempAllocator& alloc, MInstruction* at,
     21                          MDefinition* operand);
     22 
     23 // A type policy directs the type analysis phases, which insert conversion,
     24 // boxing, unboxing, and type changes as necessary.
     25 class TypePolicy {
     26 public:
     27  // Analyze the inputs of the instruction and perform one of the following
     28  // actions for each input:
     29  //  * Nothing; the input already type-checks.
     30  //  * If untyped, optionally ask the input to try and specialize its value.
     31  //  * Replace the operand with a conversion instruction.
     32  //  * Insert an unconditional deoptimization (no conversion possible).
     33  [[nodiscard]] virtual bool adjustInputs(TempAllocator& alloc,
     34                                          MInstruction* def) const = 0;
     35 };
     36 
     37 struct TypeSpecializationData {
     38 protected:
     39  // Specifies three levels of specialization:
     40  //  - < Value. This input is expected and required.
     41  //  - == None. This op should not be specialized.
     42  MIRType specialization_;
     43 
     44  MIRType thisTypeSpecialization() { return specialization_; }
     45 
     46 public:
     47  MIRType specialization() const { return specialization_; }
     48 };
     49 
     50 #define EMPTY_DATA_                            \
     51  struct Data {                                \
     52    static const TypePolicy* thisTypePolicy(); \
     53  }
     54 
     55 #define INHERIT_DATA_(DATA_TYPE)               \
     56  struct Data : public DATA_TYPE {             \
     57    static const TypePolicy* thisTypePolicy(); \
     58  }
     59 
     60 #define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
     61 
     62 class NoTypePolicy {
     63 public:
     64  struct Data {
     65    static const TypePolicy* thisTypePolicy() { return nullptr; }
     66  };
     67 };
     68 
     69 class BoxInputsPolicy final : public TypePolicy {
     70 public:
     71  constexpr BoxInputsPolicy() = default;
     72  EMPTY_DATA_;
     73  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
     74                                               MInstruction* def);
     75  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
     76                                  MInstruction* def) const override {
     77    return staticAdjustInputs(alloc, def);
     78  }
     79 };
     80 
     81 class ArithPolicy final : public TypePolicy {
     82 public:
     83  constexpr ArithPolicy() = default;
     84  EMPTY_DATA_;
     85  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
     86                                  MInstruction* def) const override;
     87 };
     88 
     89 class BigIntArithPolicy final : public TypePolicy {
     90 public:
     91  constexpr BigIntArithPolicy() = default;
     92  EMPTY_DATA_;
     93  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
     94                                  MInstruction* def) const override;
     95 };
     96 
     97 class AllDoublePolicy final : public TypePolicy {
     98 public:
     99  constexpr AllDoublePolicy() = default;
    100  EMPTY_DATA_;
    101  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    102                                               MInstruction* def);
    103  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    104                                  MInstruction* def) const override {
    105    return staticAdjustInputs(alloc, def);
    106  }
    107 };
    108 
    109 class BitwisePolicy final : public TypePolicy {
    110 public:
    111  constexpr BitwisePolicy() = default;
    112  EMPTY_DATA_;
    113  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    114                                  MInstruction* def) const override;
    115 };
    116 
    117 class ComparePolicy final : public TypePolicy {
    118 public:
    119  constexpr ComparePolicy() = default;
    120  EMPTY_DATA_;
    121  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    122                                  MInstruction* def) const override;
    123 };
    124 
    125 // Policy for MTest instructions.
    126 class TestPolicy final : public TypePolicy {
    127 public:
    128  constexpr TestPolicy() = default;
    129  EMPTY_DATA_;
    130  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    131                                  MInstruction* ins) const override;
    132 };
    133 
    134 class CallPolicy final : public TypePolicy {
    135 public:
    136  constexpr CallPolicy() = default;
    137  EMPTY_DATA_;
    138  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    139                                  MInstruction* def) const override;
    140 };
    141 
    142 // Policy for MPow:
    143 //
    144 // * If return type is MIRType::Double, we need (Double, Double) or
    145 //   (Double, Int32) operands.
    146 // * If return type is MIRType::Int32, we need (Int32, Int32) operands.
    147 class PowPolicy final : public TypePolicy {
    148 public:
    149  constexpr PowPolicy() = default;
    150  EMPTY_DATA_;
    151  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    152                                  MInstruction* ins) const override;
    153 };
    154 
    155 // Policy for MSign. Operand is either Double or Int32.
    156 class SignPolicy final : public TypePolicy {
    157 public:
    158  constexpr SignPolicy() = default;
    159  SPECIALIZATION_DATA_;
    160  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    161                                  MInstruction* ins) const override;
    162 };
    163 
    164 // Expect a symbol for operand Op. If the input is a Value, it is unboxed.
    165 template <unsigned Op>
    166 class SymbolPolicy final : public TypePolicy {
    167 public:
    168  constexpr SymbolPolicy() = default;
    169  EMPTY_DATA_;
    170  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    171                                               MInstruction* def);
    172  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    173                                  MInstruction* def) const override {
    174    return staticAdjustInputs(alloc, def);
    175  }
    176 };
    177 
    178 // Expect a boolean for operand Op. If the input is a Value, it is unboxed.
    179 template <unsigned Op>
    180 class BooleanPolicy final : public TypePolicy {
    181 public:
    182  constexpr BooleanPolicy() = default;
    183  EMPTY_DATA_;
    184  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    185                                               MInstruction* def);
    186  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    187                                  MInstruction* def) const override {
    188    return staticAdjustInputs(alloc, def);
    189  }
    190 };
    191 
    192 // Expect a string for operand Op. If the input is a Value, it is unboxed.
    193 template <unsigned Op>
    194 class StringPolicy final : public TypePolicy {
    195 public:
    196  constexpr StringPolicy() = default;
    197  EMPTY_DATA_;
    198  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    199                                               MInstruction* def);
    200  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    201                                  MInstruction* def) const override {
    202    return staticAdjustInputs(alloc, def);
    203  }
    204 };
    205 
    206 // Expect a string for operand Op. Else a ToString instruction is inserted.
    207 template <unsigned Op>
    208 class ConvertToStringPolicy final : public TypePolicy {
    209 public:
    210  constexpr ConvertToStringPolicy() = default;
    211  EMPTY_DATA_;
    212  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    213                                               MInstruction* def);
    214  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    215                                  MInstruction* def) const override {
    216    return staticAdjustInputs(alloc, def);
    217  }
    218 };
    219 
    220 // Expect a BigInt for operand Op. If the input is a Value, it is unboxed.
    221 template <unsigned Op>
    222 class BigIntPolicy final : public TypePolicy {
    223 public:
    224  constexpr BigIntPolicy() = default;
    225  EMPTY_DATA_;
    226  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    227                                               MInstruction* def);
    228  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    229                                  MInstruction* def) const override {
    230    return staticAdjustInputs(alloc, def);
    231  }
    232 };
    233 
    234 // Expects either an Int32 or a boxed Int32 for operand Op; may unbox if needed.
    235 template <unsigned Op>
    236 class UnboxedInt32Policy final : private TypePolicy {
    237 public:
    238  constexpr UnboxedInt32Policy() = default;
    239  EMPTY_DATA_;
    240  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    241                                               MInstruction* def);
    242  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    243                                  MInstruction* def) const override {
    244    return staticAdjustInputs(alloc, def);
    245  }
    246 };
    247 
    248 // Expects either an Int32 or IntPtr for operand Op.
    249 template <unsigned Op>
    250 class Int32OrIntPtrPolicy final : private TypePolicy {
    251 public:
    252  constexpr Int32OrIntPtrPolicy() = default;
    253  EMPTY_DATA_;
    254  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    255                                               MInstruction* def);
    256  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    257                                  MInstruction* def) const override {
    258    return staticAdjustInputs(alloc, def);
    259  }
    260 };
    261 
    262 // Expect an IntPtr for operand Op.
    263 template <unsigned Op>
    264 class IntPtrPolicy final : private TypePolicy {
    265 public:
    266  constexpr IntPtrPolicy() = default;
    267  EMPTY_DATA_;
    268  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    269                                               MInstruction* def);
    270  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    271                                  MInstruction* def) const override {
    272    return staticAdjustInputs(alloc, def);
    273  }
    274 };
    275 
    276 // Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
    277 template <unsigned Op>
    278 class ConvertToInt32Policy final : public TypePolicy {
    279 public:
    280  constexpr ConvertToInt32Policy() = default;
    281  EMPTY_DATA_;
    282  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    283                                               MInstruction* def);
    284  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    285                                  MInstruction* def) const override {
    286    return staticAdjustInputs(alloc, def);
    287  }
    288 };
    289 
    290 // Expect either an Int32 or Int64 for operand Op. Else a TruncateToInt32 or
    291 // ToInt64 instruction is inserted.
    292 template <unsigned Op>
    293 class TruncateToInt32OrToInt64Policy final : public TypePolicy {
    294 public:
    295  constexpr TruncateToInt32OrToInt64Policy() = default;
    296  EMPTY_DATA_;
    297  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    298                                               MInstruction* def);
    299  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    300                                  MInstruction* def) const override {
    301    return staticAdjustInputs(alloc, def);
    302  }
    303 };
    304 
    305 // Expect a double for operand Op. If the input is a Value, it is unboxed.
    306 template <unsigned Op>
    307 class DoublePolicy final : public TypePolicy {
    308 public:
    309  constexpr DoublePolicy() = default;
    310  EMPTY_DATA_;
    311  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    312                                               MInstruction* def);
    313  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    314                                  MInstruction* def) const override {
    315    return staticAdjustInputs(alloc, def);
    316  }
    317 };
    318 
    319 // Expect a float32 for operand Op. If the input is a Value, it is unboxed.
    320 template <unsigned Op>
    321 class Float32Policy final : public TypePolicy {
    322 public:
    323  constexpr Float32Policy() = default;
    324  EMPTY_DATA_;
    325  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    326                                               MInstruction* def);
    327  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    328                                  MInstruction* def) const override {
    329    return staticAdjustInputs(alloc, def);
    330  }
    331 };
    332 
    333 // Expect a float32 OR a double for operand Op, but will prioritize Float32
    334 // if the result type is set as such. If the input is a Value, it is unboxed.
    335 template <unsigned Op>
    336 class FloatingPointPolicy final : public TypePolicy {
    337 public:
    338  constexpr FloatingPointPolicy() = default;
    339  SPECIALIZATION_DATA_;
    340  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    341                                  MInstruction* def) const override;
    342 };
    343 
    344 template <unsigned Op>
    345 class NoFloatPolicy final : public TypePolicy {
    346 public:
    347  constexpr NoFloatPolicy() = default;
    348  EMPTY_DATA_;
    349  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    350                                               MInstruction* def);
    351  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    352                                  MInstruction* def) const override {
    353    return staticAdjustInputs(alloc, def);
    354  }
    355 };
    356 
    357 // Policy for guarding variadic instructions such as object / array state
    358 // instructions.
    359 template <unsigned FirstOp>
    360 class NoFloatPolicyAfter final : public TypePolicy {
    361 public:
    362  constexpr NoFloatPolicyAfter() = default;
    363  EMPTY_DATA_;
    364  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    365                                               MInstruction* def);
    366  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    367                                  MInstruction* ins) const override {
    368    return staticAdjustInputs(alloc, ins);
    369  }
    370 };
    371 
    372 // Box objects or strings as an input to a ToDouble instruction.
    373 class ToDoublePolicy final : public TypePolicy {
    374 public:
    375  constexpr ToDoublePolicy() = default;
    376  EMPTY_DATA_;
    377  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    378                                               MInstruction* def);
    379  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    380                                  MInstruction* def) const override {
    381    return staticAdjustInputs(alloc, def);
    382  }
    383 };
    384 
    385 // Box objects, strings and undefined as input to a ToInt32 instruction.
    386 class ToInt32Policy final : public TypePolicy {
    387 public:
    388  constexpr ToInt32Policy() = default;
    389  EMPTY_DATA_;
    390  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    391                                               MInstruction* def);
    392  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    393                                  MInstruction* def) const override {
    394    return staticAdjustInputs(alloc, def);
    395  }
    396 };
    397 
    398 // Box any non-BigInts as input to a ToBigInt instruction.
    399 class ToBigIntPolicy final : public TypePolicy {
    400 public:
    401  constexpr ToBigIntPolicy() = default;
    402  EMPTY_DATA_;
    403  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    404                                               MInstruction* def);
    405  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    406                                  MInstruction* def) const override {
    407    return staticAdjustInputs(alloc, def);
    408  }
    409 };
    410 
    411 // Box objects as input to a ToString instruction.
    412 class ToStringPolicy final : public TypePolicy {
    413 public:
    414  constexpr ToStringPolicy() = default;
    415  EMPTY_DATA_;
    416  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    417                                               MInstruction* def);
    418  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    419                                  MInstruction* def) const override {
    420    return staticAdjustInputs(alloc, def);
    421  }
    422 };
    423 
    424 // Box non-Boolean, non-String, non-BigInt as input to a ToInt64 instruction.
    425 class ToInt64Policy final : public TypePolicy {
    426 public:
    427  constexpr ToInt64Policy() = default;
    428  EMPTY_DATA_;
    429  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    430                                               MInstruction* ins);
    431  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    432                                  MInstruction* ins) const override {
    433    return staticAdjustInputs(alloc, ins);
    434  }
    435 };
    436 
    437 template <unsigned Op>
    438 class ObjectPolicy final : public TypePolicy {
    439 public:
    440  constexpr ObjectPolicy() = default;
    441  EMPTY_DATA_;
    442  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    443                                               MInstruction* ins);
    444  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    445                                  MInstruction* ins) const override {
    446    return staticAdjustInputs(alloc, ins);
    447  }
    448 };
    449 
    450 // Single-object input. If the input is a Value, it is unboxed. If it is
    451 // a primitive, we use ValueToNonNullObject.
    452 using SingleObjectPolicy = ObjectPolicy<0>;
    453 
    454 template <unsigned Op>
    455 class BoxPolicy final : public TypePolicy {
    456 public:
    457  constexpr BoxPolicy() = default;
    458  EMPTY_DATA_;
    459  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    460                                               MInstruction* ins);
    461  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    462                                  MInstruction* ins) const override {
    463    return staticAdjustInputs(alloc, ins);
    464  }
    465 };
    466 
    467 // Boxes everything except inputs of type Type.
    468 template <unsigned Op, MIRType Type>
    469 class BoxExceptPolicy final : public TypePolicy {
    470 public:
    471  constexpr BoxExceptPolicy() = default;
    472  EMPTY_DATA_;
    473  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    474                                               MInstruction* ins);
    475  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    476                                  MInstruction* ins) const override {
    477    return staticAdjustInputs(alloc, ins);
    478  }
    479 };
    480 
    481 // Box if not a typical property id (string, symbol, int32).
    482 template <unsigned Op>
    483 class CacheIdPolicy final : public TypePolicy {
    484 public:
    485  EMPTY_DATA_;
    486  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    487                                               MInstruction* ins);
    488  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    489                                  MInstruction* ins) const override {
    490    return staticAdjustInputs(alloc, ins);
    491  }
    492 };
    493 
    494 // Combine multiple policies.
    495 template <class... Policies>
    496 class MixPolicy final : public TypePolicy {
    497 public:
    498  constexpr MixPolicy() = default;
    499  EMPTY_DATA_;
    500  [[nodiscard]] static bool staticAdjustInputs(TempAllocator& alloc,
    501                                               MInstruction* ins) {
    502    return (Policies::staticAdjustInputs(alloc, ins) && ...);
    503  }
    504  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    505                                  MInstruction* ins) const override {
    506    return staticAdjustInputs(alloc, ins);
    507  }
    508 };
    509 
    510 class MegamorphicSetElementPolicy final : public TypePolicy {
    511 public:
    512  constexpr MegamorphicSetElementPolicy() = default;
    513  EMPTY_DATA_;
    514  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    515                                  MInstruction* def) const override;
    516 };
    517 
    518 class StoreDataViewElementPolicy;
    519 class StoreTypedArrayHolePolicy;
    520 
    521 class StoreUnboxedScalarPolicy : public TypePolicy {
    522 private:
    523  constexpr StoreUnboxedScalarPolicy() = default;
    524  [[nodiscard]] static bool adjustValueInput(TempAllocator& alloc,
    525                                             MInstruction* ins,
    526                                             Scalar::Type arrayType,
    527                                             MDefinition* value,
    528                                             int valueOperand);
    529 
    530  friend class StoreDataViewElementPolicy;
    531  friend class StoreTypedArrayHolePolicy;
    532  friend class TypedArrayFillPolicy;
    533 
    534 public:
    535  EMPTY_DATA_;
    536  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    537                                  MInstruction* ins) const override;
    538 };
    539 
    540 class StoreDataViewElementPolicy final : public StoreUnboxedScalarPolicy {
    541 public:
    542  constexpr StoreDataViewElementPolicy() = default;
    543  EMPTY_DATA_;
    544  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    545                                  MInstruction* ins) const override;
    546 };
    547 
    548 class StoreTypedArrayHolePolicy final : public StoreUnboxedScalarPolicy {
    549 public:
    550  constexpr StoreTypedArrayHolePolicy() = default;
    551  EMPTY_DATA_;
    552  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    553                                  MInstruction* ins) const override;
    554 };
    555 
    556 class TypedArrayFillPolicy final : public StoreUnboxedScalarPolicy {
    557 public:
    558  constexpr TypedArrayFillPolicy() = default;
    559  EMPTY_DATA_;
    560  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    561                                  MInstruction* ins) const override;
    562 };
    563 
    564 // Accepts integers and doubles. Everything else is boxed.
    565 class ClampPolicy final : public TypePolicy {
    566 public:
    567  constexpr ClampPolicy() = default;
    568  EMPTY_DATA_;
    569  [[nodiscard]] bool adjustInputs(TempAllocator& alloc,
    570                                  MInstruction* ins) const override;
    571 };
    572 
    573 #undef SPECIALIZATION_DATA_
    574 #undef INHERIT_DATA_
    575 #undef EMPTY_DATA_
    576 
    577 }  // namespace jit
    578 }  // namespace js
    579 
    580 #endif /* jit_TypePolicy_h */