tor-browser

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

BaselineIC.h (17946B)


      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_BaselineIC_h
      8 #define jit_BaselineIC_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Attributes.h"
     12 
     13 #include <stddef.h>
     14 #include <stdint.h>
     15 
     16 #include "jit/ICState.h"
     17 #include "jit/JitCode.h"
     18 #include "jit/shared/Assembler-shared.h"
     19 #include "jit/TypeData.h"
     20 #include "js/TypeDecls.h"
     21 
     22 class JS_PUBLIC_API JSTracer;
     23 
     24 enum class JSOp : uint8_t;
     25 
     26 namespace js {
     27 
     28 MOZ_COLD void ReportOutOfMemory(JSContext* cx);
     29 
     30 namespace jit {
     31 
     32 class BaselineFrame;
     33 class CacheIRStubInfo;
     34 class ICScript;
     35 class ICStubSpace;
     36 
     37 enum class VMFunctionId;
     38 
     39 // [SMDOC] JIT Inline Caches (ICs)
     40 //
     41 // Baseline Inline Caches are polymorphic caches that aggressively
     42 // share their stub code.
     43 //
     44 // Every polymorphic site contains a linked list of stubs which are
     45 // specific to that site.  These stubs are composed of a |StubData|
     46 // structure that stores parametrization information (e.g.
     47 // the shape pointer for a shape-check-and-property-get stub), any
     48 // dynamic information (e.g. warm-up counters), a pointer to the stub code,
     49 // and a pointer to the next stub state in the linked list.
     50 //
     51 // Every BaselineScript keeps an table of |CacheDescriptor| data
     52 // structures, which store the following:
     53 //      A pointer to the first StubData in the cache.
     54 //      The bytecode PC of the relevant IC.
     55 //      The machine-code PC where the call to the stubcode returns.
     56 //
     57 // A diagram:
     58 //
     59 //        Control flow                  Pointers
     60 //      =======#                     ----.     .---->
     61 //             #                         |     |
     62 //             #======>                  \-----/
     63 //
     64 //
     65 //                                   .---------------------------------------.
     66 //                                   |         .-------------------------.   |
     67 //                                   |         |         .----.          |   |
     68 //         Baseline                  |         |         |    |          |   |
     69 //         JIT Code              0   ^     1   ^     2   ^    |          |   |
     70 //     +--------------+    .-->+-----+   +-----+   +-----+    |          |   |
     71 //     |              |  #=|==>|     |==>|     |==>| FB  |    |          |   |
     72 //     |              |  # |   +-----+   +-----+   +-----+    |          |   |
     73 //     |              |  # |      #         #         #       |          |   |
     74 //     |==============|==# |      #         #         #       |          |   |
     75 //     |=== IC =======|    |      #         #         #       |          |   |
     76 //  .->|==============|<===|======#=========#=========#       |          |   |
     77 //  |  |              |    |                                  |          |   |
     78 //  |  |              |    |                                  |          |   |
     79 //  |  |              |    |                                  |          |   |
     80 //  |  |              |    |                                  v          |   |
     81 //  |  |              |    |                              +---------+    |   |
     82 //  |  |              |    |                              | Fallback|    |   |
     83 //  |  |              |    |                              | Stub    |    |   |
     84 //  |  |              |    |                              | Code    |    |   |
     85 //  |  |              |    |                              +---------+    |   |
     86 //  |  +--------------+    |                                             |   |
     87 //  |         |_______     |                              +---------+    |   |
     88 //  |                |     |                              | Stub    |<---/   |
     89 //  |        IC      |     \--.                           | Code    |        |
     90 //  |    Descriptor  |        |                           +---------+        |
     91 //  |      Table     v        |                                              |
     92 //  |  +-----------------+    |                           +---------+        |
     93 //  \--| Ins | PC | Stub |----/                           | Stub    |<-------/
     94 //     +-----------------+                                | Code    |
     95 //     |       ...       |                                +---------+
     96 //     +-----------------+
     97 //                                                          Shared
     98 //                                                          Stub Code
     99 //
    100 
    101 class ICStub;
    102 class ICCacheIRStub;
    103 class ICFallbackStub;
    104 
    105 #ifdef JS_JITSPEW
    106 void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
    107    MOZ_FORMAT_PRINTF(3, 4);
    108 #else
    109 #  define FallbackICSpew(...)
    110 #endif
    111 
    112 // An entry in the ICScript IC table. There's one ICEntry per IC.
    113 class ICEntry {
    114  // A pointer to the first IC stub for this instruction.
    115  ICStub* firstStub_;
    116 
    117 public:
    118  explicit ICEntry(ICStub* firstStub) : firstStub_(firstStub) {}
    119 
    120  ICStub* firstStub() const {
    121    MOZ_ASSERT(firstStub_);
    122    return firstStub_;
    123  }
    124 
    125  void setFirstStub(ICStub* stub) { firstStub_ = stub; }
    126 
    127  static constexpr size_t offsetOfFirstStub() {
    128    return offsetof(ICEntry, firstStub_);
    129  }
    130 
    131  void trace(JSTracer* trc, ICFallbackStub* fallbackStub);
    132  bool traceWeak(JSTracer* trc, ICFallbackStub* fallbackStub);
    133 };
    134 
    135 //
    136 // Base class for all IC stubs.
    137 //
    138 class ICStub {
    139  friend class ICFallbackStub;
    140 
    141 protected:
    142  // The raw jitcode to call for this stub.
    143  uint8_t* stubCode_;
    144 
    145  // Counts the number of times the stub was entered
    146  //
    147  // See Bug 1494473 comment 6 for a mechanism to handle overflow if overflow
    148  // becomes a concern.
    149  uint32_t enteredCount_ = 0;
    150 
    151  // Tracks input types for some CacheIR stubs, to help optimize
    152  // polymorphic cases. Stored in the base class to make use of
    153  // padding bytes.
    154  TypeData typeData_;
    155 
    156  // Whether this is an ICFallbackStub or an ICCacheIRStub.
    157  bool isFallback_;
    158 
    159  ICStub(uint8_t* stubCode, bool isFallback)
    160      : stubCode_(stubCode), isFallback_(isFallback) {
    161 #ifndef ENABLE_PORTABLE_BASELINE_INTERP
    162    MOZ_ASSERT(stubCode != nullptr);
    163 #endif  // !ENABLE_PORTABLE_BASELINE_INTERP
    164  }
    165 
    166 public:
    167  inline bool isFallback() const { return isFallback_; }
    168 
    169  inline ICStub* maybeNext() const;
    170 
    171  inline const ICFallbackStub* toFallbackStub() const {
    172    MOZ_ASSERT(isFallback());
    173    return reinterpret_cast<const ICFallbackStub*>(this);
    174  }
    175 
    176  inline ICFallbackStub* toFallbackStub() {
    177    MOZ_ASSERT(isFallback());
    178    return reinterpret_cast<ICFallbackStub*>(this);
    179  }
    180 
    181  ICCacheIRStub* toCacheIRStub() {
    182    MOZ_ASSERT(!isFallback());
    183    return reinterpret_cast<ICCacheIRStub*>(this);
    184  }
    185  const ICCacheIRStub* toCacheIRStub() const {
    186    MOZ_ASSERT(!isFallback());
    187    return reinterpret_cast<const ICCacheIRStub*>(this);
    188  }
    189 
    190  bool usesTrampolineCode() const {
    191    // All fallback code is stored in a single JitCode instance, so we can't
    192    // call JitCode::FromExecutable on the raw pointer.
    193    return isFallback();
    194  }
    195 
    196 #ifndef ENABLE_PORTABLE_BASELINE_INTERP
    197  JitCode* jitCode() {
    198    MOZ_ASSERT(!usesTrampolineCode());
    199    return JitCode::FromExecutable(stubCode_);
    200  }
    201  bool hasJitCode() { return !!stubCode_; }
    202 #else  // !ENABLE_PORTABLE_BASELINE_INTERP
    203  JitCode* jitCode() { return nullptr; }
    204  bool hasJitCode() { return false; }
    205  uint8_t* rawJitCode() const { return stubCode_; }
    206  void updateRawJitCode(uint8_t* ptr) { stubCode_ = ptr; }
    207 #endif
    208 
    209  uint32_t enteredCount() const { return enteredCount_; }
    210  inline void incrementEnteredCount() { enteredCount_++; }
    211  void resetEnteredCount() { enteredCount_ = 0; }
    212 
    213  static constexpr size_t offsetOfStubCode() {
    214    return offsetof(ICStub, stubCode_);
    215  }
    216  static constexpr size_t offsetOfEnteredCount() {
    217    return offsetof(ICStub, enteredCount_);
    218  }
    219 };
    220 
    221 class ICFallbackStub final : public ICStub {
    222  friend class ICStubConstIterator;
    223 
    224 protected:
    225  // The PC offset of this IC's bytecode op within the JSScript.
    226  uint32_t pcOffset_;
    227 
    228  // The state of this IC.
    229  ICState state_{};
    230 
    231 public:
    232  explicit ICFallbackStub(uint32_t pcOffset, TrampolinePtr stubCode)
    233      : ICStub(stubCode.value, /* isFallback = */ true), pcOffset_(pcOffset) {}
    234 
    235  inline size_t numOptimizedStubs() const { return state_.numOptimizedStubs(); }
    236 
    237  bool newStubIsFirstStub() const { return state_.newStubIsFirstStub(); }
    238 
    239  ICState& state() { return state_; }
    240 
    241  uint32_t pcOffset() const { return pcOffset_; }
    242 
    243  // Add a new stub to the IC chain terminated by this fallback stub.
    244  inline void addNewStub(ICEntry* icEntry, ICCacheIRStub* stub);
    245 
    246  void discardStubs(Zone* zone, ICEntry* icEntry);
    247 
    248  void clearUsedByTranspiler() { state_.clearUsedByTranspiler(); }
    249  void setUsedByTranspiler() { state_.setUsedByTranspiler(); }
    250  bool usedByTranspiler() const { return state_.usedByTranspiler(); }
    251 
    252  void clearMayHaveFoldedStub() { state_.clearMayHaveFoldedStub(); }
    253  void setMayHaveFoldedStub() { state_.setMayHaveFoldedStub(); }
    254  bool mayHaveFoldedStub() const { return state_.mayHaveFoldedStub(); }
    255 
    256  TrialInliningState trialInliningState() const {
    257    return state_.trialInliningState();
    258  }
    259  void setTrialInliningState(TrialInliningState state) {
    260    state_.setTrialInliningState(state);
    261  }
    262 
    263  void trackNotAttached();
    264 
    265  void unlinkStub(Zone* zone, ICEntry* icEntry, ICCacheIRStub* prev,
    266                  ICCacheIRStub* stub);
    267  void unlinkStubUnbarriered(ICEntry* icEntry, ICCacheIRStub* prev,
    268                             ICCacheIRStub* stub);
    269 };
    270 
    271 class ICCacheIRStub final : public ICStub {
    272  // Pointer to next IC stub.
    273  ICStub* next_ = nullptr;
    274 
    275  const CacheIRStubInfo* stubInfo_;
    276 
    277 #ifndef JS_64BIT
    278  // Ensure stub data is 8-byte aligned on 32-bit.
    279  uintptr_t padding_ = 0;
    280 #endif
    281 
    282 public:
    283  ICCacheIRStub(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
    284      : ICStub(stubCode ? stubCode->raw() : nullptr, /* isFallback = */ false),
    285        stubInfo_(stubInfo) {
    286    MOZ_ASSERT_IF(!IsPortableBaselineInterpreterEnabled(), stubCode);
    287  }
    288 
    289  ICStub* next() const { return next_; }
    290  void setNext(ICStub* stub) { next_ = stub; }
    291 
    292  ICCacheIRStub* nextCacheIR() const {
    293    return next_->isFallback() ? nullptr : next_->toCacheIRStub();
    294  }
    295 
    296  const CacheIRStubInfo* stubInfo() const { return stubInfo_; }
    297  uint8_t* stubDataStart();
    298 
    299  void trace(JSTracer* trc);
    300  bool traceWeak(JSTracer* trc);
    301 
    302  ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace);
    303 
    304  // Returns true if this stub can call JS or VM code that can trigger a GC.
    305  bool makesGCCalls() const;
    306 
    307  static constexpr size_t offsetOfNext() {
    308    return offsetof(ICCacheIRStub, next_);
    309  }
    310 
    311  void setTypeData(TypeData data) { typeData_ = data; }
    312  TypeData typeData() const { return typeData_; }
    313 };
    314 
    315 // Assert stub size is what we expect to catch regressions.
    316 #ifdef JS_64BIT
    317 static_assert(sizeof(ICFallbackStub) == 3 * sizeof(uintptr_t));
    318 static_assert(sizeof(ICCacheIRStub) == 4 * sizeof(uintptr_t));
    319 #else
    320 static_assert(sizeof(ICFallbackStub) == 5 * sizeof(uintptr_t));
    321 static_assert(sizeof(ICCacheIRStub) == 6 * sizeof(uintptr_t));
    322 #endif
    323 
    324 inline ICStub* ICStub::maybeNext() const {
    325  return isFallback() ? nullptr : toCacheIRStub()->next();
    326 }
    327 
    328 inline void ICFallbackStub::addNewStub(ICEntry* icEntry, ICCacheIRStub* stub) {
    329  MOZ_ASSERT(stub->next() == nullptr);
    330  stub->setNext(icEntry->firstStub());
    331  icEntry->setFirstStub(stub);
    332  state_.trackAttached();
    333 }
    334 
    335 AllocatableGeneralRegisterSet BaselineICAvailableGeneralRegs(size_t numInputs);
    336 
    337 bool ICSupportsPolymorphicTypeData(JSOp op);
    338 
    339 struct IonOsrTempData;
    340 
    341 extern bool DoCallFallback(JSContext* cx, BaselineFrame* frame,
    342                           ICFallbackStub* stub, uint32_t argc, Value* vp,
    343                           MutableHandleValue res);
    344 
    345 extern bool DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
    346                                 ICFallbackStub* stub, Value* vp,
    347                                 MutableHandleValue res);
    348 
    349 extern bool DoToBoolFallback(JSContext* cx, BaselineFrame* frame,
    350                             ICFallbackStub* stub, HandleValue arg,
    351                             MutableHandleValue ret);
    352 
    353 extern bool DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame,
    354                                   ICFallbackStub* stub, HandleValue lhs,
    355                                   HandleValue rhs, HandleValue receiver,
    356                                   MutableHandleValue res);
    357 
    358 extern bool DoGetElemFallback(JSContext* cx, BaselineFrame* frame,
    359                              ICFallbackStub* stub, HandleValue lhs,
    360                              HandleValue rhs, MutableHandleValue res);
    361 
    362 extern bool DoSetElemFallback(JSContext* cx, BaselineFrame* frame,
    363                              ICFallbackStub* stub, Value* stack,
    364                              HandleValue objv, HandleValue index,
    365                              HandleValue rhs);
    366 
    367 extern bool DoInFallback(JSContext* cx, BaselineFrame* frame,
    368                         ICFallbackStub* stub, HandleValue key,
    369                         HandleValue objValue, MutableHandleValue res);
    370 
    371 extern bool DoHasOwnFallback(JSContext* cx, BaselineFrame* frame,
    372                             ICFallbackStub* stub, HandleValue keyValue,
    373                             HandleValue objValue, MutableHandleValue res);
    374 
    375 extern bool DoCheckPrivateFieldFallback(JSContext* cx, BaselineFrame* frame,
    376                                        ICFallbackStub* stub,
    377                                        HandleValue objValue,
    378                                        HandleValue keyValue,
    379                                        MutableHandleValue res);
    380 
    381 extern bool DoGetNameFallback(JSContext* cx, BaselineFrame* frame,
    382                              ICFallbackStub* stub, HandleObject envChain,
    383                              MutableHandleValue res);
    384 
    385 extern bool DoBindNameFallback(JSContext* cx, BaselineFrame* frame,
    386                               ICFallbackStub* stub, HandleObject envChain,
    387                               MutableHandleValue res);
    388 
    389 extern bool DoLazyConstantFallback(JSContext* cx, BaselineFrame* frame,
    390                                   ICFallbackStub* stub,
    391                                   MutableHandleValue res);
    392 
    393 extern bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame,
    394                              ICFallbackStub* stub, HandleValue val,
    395                              MutableHandleValue res);
    396 
    397 extern bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame,
    398                                   ICFallbackStub* stub, HandleValue receiver,
    399                                   HandleValue val, MutableHandleValue res);
    400 
    401 extern bool DoSetPropFallback(JSContext* cx, BaselineFrame* frame,
    402                              ICFallbackStub* stub, Value* stack,
    403                              HandleValue lhs, HandleValue rhs);
    404 
    405 extern bool DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
    406                                  ICFallbackStub* stub, HandleValue value,
    407                                  MutableHandleValue res);
    408 
    409 extern bool DoOptimizeSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
    410                                         ICFallbackStub* stub,
    411                                         HandleValue value,
    412                                         MutableHandleValue res);
    413 
    414 extern bool DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame,
    415                                 ICFallbackStub* stub, HandleValue lhs,
    416                                 HandleValue rhs, MutableHandleValue res);
    417 
    418 extern bool DoTypeOfFallback(JSContext* cx, BaselineFrame* frame,
    419                             ICFallbackStub* stub, HandleValue val,
    420                             MutableHandleValue res);
    421 
    422 extern bool DoTypeOfEqFallback(JSContext* cx, BaselineFrame* frame,
    423                               ICFallbackStub* stub, HandleValue val,
    424                               MutableHandleValue res);
    425 
    426 extern bool DoToPropertyKeyFallback(JSContext* cx, BaselineFrame* frame,
    427                                    ICFallbackStub* stub, HandleValue val,
    428                                    MutableHandleValue res);
    429 
    430 extern bool DoRestFallback(JSContext* cx, BaselineFrame* frame,
    431                           ICFallbackStub* stub, MutableHandleValue res);
    432 
    433 extern bool DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame,
    434                                 ICFallbackStub* stub, HandleValue val,
    435                                 MutableHandleValue res);
    436 
    437 extern bool DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame,
    438                                  ICFallbackStub* stub, HandleValue lhs,
    439                                  HandleValue rhs, MutableHandleValue ret);
    440 
    441 extern bool DoNewArrayFallback(JSContext* cx, BaselineFrame* frame,
    442                               ICFallbackStub* stub, MutableHandleValue res);
    443 
    444 extern bool DoNewObjectFallback(JSContext* cx, BaselineFrame* frame,
    445                                ICFallbackStub* stub, MutableHandleValue res);
    446 
    447 extern bool DoLambdaFallback(JSContext* cx, BaselineFrame* frame,
    448                             ICFallbackStub* stub, MutableHandleValue res);
    449 
    450 extern bool DoCompareFallback(JSContext* cx, BaselineFrame* frame,
    451                              ICFallbackStub* stub, HandleValue lhs,
    452                              HandleValue rhs, MutableHandleValue ret);
    453 
    454 extern bool DoCloseIterFallback(JSContext* cx, BaselineFrame* frame,
    455                                ICFallbackStub* stub, HandleObject iter);
    456 
    457 extern bool DoOptimizeGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
    458                                          ICFallbackStub* stub,
    459                                          HandleValue value,
    460                                          MutableHandleValue res);
    461 extern bool DoGetImportFallback(JSContext* cx, BaselineFrame* frame,
    462                                ICFallbackStub* stub, MutableHandleValue res);
    463 
    464 }  // namespace jit
    465 }  // namespace js
    466 
    467 #endif /* jit_BaselineIC_h */