LCOV - code coverage report
Current view: top level - js/src/jit - JitcodeMap.h (source / functions) Hit Total Coverage
Test: output.info Lines: 123 510 24.1 %
Date: 2017-07-14 16:53:18 Functions: 38 129 29.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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_JitcodeMap_h
       8             : #define jit_JitcodeMap_h
       9             : 
      10             : #include "jit/CompactBuffer.h"
      11             : #include "jit/CompileInfo.h"
      12             : #include "jit/ExecutableAllocator.h"
      13             : #include "jit/OptimizationTracking.h"
      14             : #include "jit/shared/CodeGenerator-shared.h"
      15             : 
      16             : namespace js {
      17             : namespace jit {
      18             : 
      19             : /*
      20             :  * The Ion jitcode map implements tables to allow mapping from addresses in ion jitcode
      21             :  * to the list of (JSScript*, jsbytecode*) pairs that are implicitly active in the frame at
      22             :  * that point in the native code.
      23             :  *
      24             :  * To represent this information efficiently, a multi-level table is used.
      25             :  *
      26             :  * At the top level, a global splay-tree of JitcodeGlobalEntry describings the mapping for
      27             :  * each individual IonCode script generated by compiles.  The entries are ordered by their
      28             :  * nativeStartAddr.
      29             :  *
      30             :  * Every entry in the table is of fixed size, but there are different entry types,
      31             :  * distinguished by the kind field.
      32             :  */
      33             : 
      34             : class JitcodeGlobalTable;
      35             : class JitcodeIonTable;
      36             : class JitcodeRegionEntry;
      37             : 
      38             : class JitcodeGlobalEntry;
      39             : 
      40             : class JitcodeSkiplistTower
      41             : {
      42             :   public:
      43             :     static const unsigned MAX_HEIGHT = 32;
      44             : 
      45             :   private:
      46             :     uint8_t height_;
      47             :     bool isFree_;
      48             :     JitcodeGlobalEntry* ptrs_[1];
      49             : 
      50             :   public:
      51         632 :     explicit JitcodeSkiplistTower(unsigned height)
      52         632 :       : height_(height),
      53         632 :         isFree_(false)
      54             :     {
      55         632 :         MOZ_ASSERT(height >= 1 && height <= MAX_HEIGHT);
      56         632 :         clearPtrs();
      57         632 :     }
      58             : 
      59       20375 :     unsigned height() const {
      60       20375 :         return height_;
      61             :     }
      62             : 
      63             :     JitcodeGlobalEntry** ptrs(unsigned level) {
      64             :         return ptrs_;
      65             :     }
      66             : 
      67       17139 :     JitcodeGlobalEntry* next(unsigned level) const {
      68       17139 :         MOZ_ASSERT(!isFree_);
      69       17139 :         MOZ_ASSERT(level < height());
      70       17139 :         return ptrs_[level];
      71             :     }
      72        2469 :     void setNext(unsigned level, JitcodeGlobalEntry* entry) {
      73        2469 :         MOZ_ASSERT(!isFree_);
      74        2469 :         MOZ_ASSERT(level < height());
      75        2469 :         ptrs_[level] = entry;
      76        2469 :     }
      77             : 
      78             :     //
      79             :     // When stored in a free-list, towers use 'ptrs_[0]' to store a
      80             :     // pointer to the next tower.  In this context only, 'ptrs_[0]'
      81             :     // may refer to a |JitcodeSkiplistTower*| instead of a
      82             :     // |JitcodeGlobalEntry*|.
      83             :     //
      84             : 
      85           0 :     void addToFreeList(JitcodeSkiplistTower** freeList) {
      86           0 :         JitcodeSkiplistTower* nextFreeTower = *freeList;
      87           0 :         MOZ_ASSERT_IF(nextFreeTower, nextFreeTower->isFree_ &&
      88             :                                      nextFreeTower->height() == height_);
      89           0 :         ptrs_[0] = (JitcodeGlobalEntry*) nextFreeTower;
      90           0 :         isFree_ = true;
      91           0 :         *freeList = this;
      92           0 :     }
      93             : 
      94         632 :     static JitcodeSkiplistTower* PopFromFreeList(JitcodeSkiplistTower** freeList) {
      95         632 :         if (!*freeList)
      96         632 :             return nullptr;
      97             : 
      98           0 :         JitcodeSkiplistTower* tower = *freeList;
      99           0 :         MOZ_ASSERT(tower->isFree_);
     100           0 :         JitcodeSkiplistTower* nextFreeTower = (JitcodeSkiplistTower*) tower->ptrs_[0];
     101           0 :         tower->clearPtrs();
     102           0 :         tower->isFree_ = false;
     103           0 :         *freeList = nextFreeTower;
     104           0 :         return tower;
     105             :     }
     106             : 
     107         632 :     static size_t CalculateSize(unsigned height) {
     108         632 :         MOZ_ASSERT(height >= 1);
     109             :         return sizeof(JitcodeSkiplistTower) +
     110         632 :                (sizeof(JitcodeGlobalEntry*) * (height - 1));
     111             :     }
     112             : 
     113             :   private:
     114         632 :     void clearPtrs() {
     115        1883 :         for (unsigned i = 0; i < height_; i++)
     116        1251 :             ptrs_[0] = nullptr;
     117         632 :     }
     118             : };
     119             : 
     120             : class JitcodeGlobalEntry
     121             : {
     122             :     friend class JitcodeGlobalTable;
     123             : 
     124             :   public:
     125             :     enum Kind {
     126             :         INVALID = 0,
     127             :         Ion,
     128             :         Baseline,
     129             :         IonCache,
     130             :         Dummy,
     131             :         Query,
     132             :         LIMIT
     133             :     };
     134             :     JS_STATIC_ASSERT(LIMIT <= 8);
     135             : 
     136             :     struct BytecodeLocation {
     137             :         JSScript* script;
     138             :         jsbytecode* pc;
     139           0 :         BytecodeLocation(JSScript* script, jsbytecode* pc) : script(script), pc(pc) {}
     140             :     };
     141             :     typedef Vector<BytecodeLocation, 0, SystemAllocPolicy> BytecodeLocationVector;
     142             :     typedef Vector<const char*, 0, SystemAllocPolicy> ProfileStringVector;
     143             : 
     144             :     struct BaseEntry
     145             :     {
     146             :         JitCode* jitcode_;
     147             :         void* nativeStartAddr_;
     148             :         void* nativeEndAddr_;
     149             :         uint32_t gen_;
     150             :         Kind kind_ : 7;
     151             : 
     152        1264 :         void init() {
     153        1264 :             jitcode_ = nullptr;
     154        1264 :             nativeStartAddr_ = nullptr;
     155        1264 :             nativeEndAddr_ = nullptr;
     156        1264 :             gen_ = UINT32_MAX;
     157        1264 :             kind_ = INVALID;
     158        1264 :         }
     159             : 
     160         632 :         void init(Kind kind, JitCode* code,
     161             :                   void* nativeStartAddr, void* nativeEndAddr)
     162             :         {
     163         632 :             MOZ_ASSERT_IF(kind != Query, code);
     164         632 :             MOZ_ASSERT(nativeStartAddr);
     165         632 :             MOZ_ASSERT(nativeEndAddr);
     166         632 :             MOZ_ASSERT(kind > INVALID && kind < LIMIT);
     167         632 :             jitcode_ = code;
     168         632 :             nativeStartAddr_ = nativeStartAddr;
     169         632 :             nativeEndAddr_ = nativeEndAddr;
     170         632 :             gen_ = UINT32_MAX;
     171         632 :             kind_ = kind;
     172         632 :         }
     173             : 
     174             :         uint32_t generation() const {
     175             :             return gen_;
     176             :         }
     177           0 :         void setGeneration(uint32_t gen) {
     178           0 :             gen_ = gen;
     179           0 :         }
     180           0 :         bool isSampled(uint32_t currentGen, uint32_t lapCount) {
     181           0 :             if (gen_ == UINT32_MAX || currentGen == UINT32_MAX)
     182           0 :                 return false;
     183           0 :             MOZ_ASSERT(currentGen >= gen_);
     184           0 :             return (currentGen - gen_) <= lapCount;
     185             :         }
     186             : 
     187       62336 :         Kind kind() const {
     188       62336 :             return kind_;
     189             :         }
     190           0 :         JitCode* jitcode() const {
     191           0 :             return jitcode_;
     192             :         }
     193       84263 :         void* nativeStartAddr() const {
     194       84263 :             return nativeStartAddr_;
     195             :         }
     196       59413 :         void* nativeEndAddr() const {
     197       59413 :             return nativeEndAddr_;
     198             :         }
     199             : 
     200       36258 :         bool startsBelowPointer(void* ptr) const {
     201       36258 :             return ((uint8_t*)nativeStartAddr()) <= ((uint8_t*) ptr);
     202             :         }
     203       35241 :         bool endsAbovePointer(void* ptr) const {
     204       35241 :             return ((uint8_t*)nativeEndAddr()) > ((uint8_t*) ptr);
     205             :         }
     206       24172 :         bool containsPointer(void* ptr) const {
     207       24172 :             return startsBelowPointer(ptr) && endsAbovePointer(ptr);
     208             :         }
     209             : 
     210             :         template <class ShouldTraceProvider> bool traceJitcode(JSTracer* trc);
     211             :         bool isJitcodeMarkedFromAnyThread(JSRuntime* rt);
     212             :         bool isJitcodeAboutToBeFinalized();
     213             :     };
     214             : 
     215             :     struct IonEntry : public BaseEntry
     216             :     {
     217             :         // regionTable_ points to the start of the region table within the
     218             :         // packed map for compile represented by this entry.  Since the
     219             :         // region table occurs at the tail of the memory region, this pointer
     220             :         // points somewhere inside the region memory space, and not to the start
     221             :         // of the memory space.
     222             :         JitcodeIonTable* regionTable_;
     223             : 
     224             :         // optsRegionTable_ points to the table within the compact
     225             :         // optimizations map indexing all regions that have tracked
     226             :         // optimization attempts. optsTypesTable_ is the tracked typed info
     227             :         // associated with the attempts vectors; it is the same length as the
     228             :         // attempts table. optsAttemptsTable_ is the table indexing those
     229             :         // attempts vectors.
     230             :         //
     231             :         // All pointers point into the same block of memory; the beginning of
     232             :         // the block is optRegionTable_->payloadStart().
     233             :         const IonTrackedOptimizationsRegionTable* optsRegionTable_;
     234             :         const IonTrackedOptimizationsTypesTable* optsTypesTable_;
     235             :         const IonTrackedOptimizationsAttemptsTable* optsAttemptsTable_;
     236             : 
     237             :         // The types table above records type sets, which have been gathered
     238             :         // into one vector here.
     239             :         IonTrackedTypeVector* optsAllTypes_;
     240             : 
     241             :         // Linked list pointers to allow traversing through all entries that
     242             :         // could possibly contain nursery pointers. Note that the contained
     243             :         // pointers can be mutated into nursery pointers at any time.
     244             :         IonEntry* prevNursery_;
     245             :         IonEntry* nextNursery_;
     246             : 
     247             :         struct ScriptNamePair {
     248             :             JSScript* script;
     249             :             char* str;
     250             :         };
     251             : 
     252             :         struct SizedScriptList {
     253             :             uint32_t size;
     254             :             ScriptNamePair pairs[1];
     255           0 :             SizedScriptList(uint32_t sz, JSScript** scrs, char** strs) : size(sz) {
     256           0 :                 for (uint32_t i = 0; i < size; i++) {
     257           0 :                     pairs[i].script = scrs[i];
     258           0 :                     pairs[i].str = strs[i];
     259             :                 }
     260           0 :             }
     261             : 
     262           0 :             static uint32_t AllocSizeFor(uint32_t nscripts) {
     263           0 :                 return sizeof(SizedScriptList) + ((nscripts - 1) * sizeof(ScriptNamePair));
     264             :             }
     265             :         };
     266             : 
     267             :         SizedScriptList* scriptList_;
     268             : 
     269           0 :         void init(JitCode* code, void* nativeStartAddr, void* nativeEndAddr,
     270             :                   SizedScriptList* scriptList, JitcodeIonTable* regionTable)
     271             :         {
     272           0 :             MOZ_ASSERT(scriptList);
     273           0 :             MOZ_ASSERT(regionTable);
     274           0 :             BaseEntry::init(Ion, code, nativeStartAddr, nativeEndAddr);
     275           0 :             regionTable_ = regionTable;
     276           0 :             scriptList_ = scriptList;
     277           0 :             optsRegionTable_ = nullptr;
     278           0 :             optsTypesTable_ = nullptr;
     279           0 :             optsAllTypes_ = nullptr;
     280           0 :             optsAttemptsTable_ = nullptr;
     281           0 :             prevNursery_ = nextNursery_ = nullptr;
     282           0 :         }
     283             : 
     284           0 :         void initTrackedOptimizations(const IonTrackedOptimizationsRegionTable* regionTable,
     285             :                                       const IonTrackedOptimizationsTypesTable* typesTable,
     286             :                                       const IonTrackedOptimizationsAttemptsTable* attemptsTable,
     287             :                                       IonTrackedTypeVector* allTypes)
     288             :         {
     289           0 :             optsRegionTable_ = regionTable;
     290           0 :             optsTypesTable_ = typesTable;
     291           0 :             optsAttemptsTable_ = attemptsTable;
     292           0 :             optsAllTypes_ = allTypes;
     293           0 :         }
     294             : 
     295           0 :         SizedScriptList* sizedScriptList() const {
     296           0 :             return scriptList_;
     297             :         }
     298             : 
     299           0 :         unsigned numScripts() const {
     300           0 :             return scriptList_->size;
     301             :         }
     302             : 
     303           0 :         JSScript* getScript(unsigned idx) const {
     304           0 :             MOZ_ASSERT(idx < numScripts());
     305           0 :             return sizedScriptList()->pairs[idx].script;
     306             :         }
     307             : 
     308           0 :         const char* getStr(unsigned idx) const {
     309           0 :             MOZ_ASSERT(idx < numScripts());
     310           0 :             return sizedScriptList()->pairs[idx].str;
     311             :         }
     312             : 
     313             :         void destroy();
     314             : 
     315           0 :         JitcodeIonTable* regionTable() const {
     316           0 :             return regionTable_;
     317             :         }
     318             : 
     319             :         int scriptIndex(JSScript* script) const {
     320             :             unsigned count = numScripts();
     321             :             for (unsigned i = 0; i < count; i++) {
     322             :                 if (getScript(i) == script)
     323             :                     return i;
     324             :             }
     325             :             return -1;
     326             :         }
     327             : 
     328             :         void* canonicalNativeAddrFor(JSRuntime*rt, void* ptr) const;
     329             : 
     330             :         MOZ_MUST_USE bool callStackAtAddr(JSRuntime* rt, void* ptr, BytecodeLocationVector& results,
     331             :                                           uint32_t* depth) const;
     332             : 
     333             :         uint32_t callStackAtAddr(JSRuntime* rt, void* ptr, const char** results,
     334             :                                  uint32_t maxResults) const;
     335             : 
     336             :         void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
     337             :                                          JSScript** script, jsbytecode** pc) const;
     338             : 
     339           0 :         bool hasTrackedOptimizations() const {
     340           0 :             return !!optsRegionTable_;
     341             :         }
     342             : 
     343             :         const IonTrackedOptimizationsRegionTable* trackedOptimizationsRegionTable() const {
     344             :             MOZ_ASSERT(hasTrackedOptimizations());
     345             :             return optsRegionTable_;
     346             :         }
     347             : 
     348             :         uint8_t numOptimizationAttempts() const {
     349             :             MOZ_ASSERT(hasTrackedOptimizations());
     350             :             return optsAttemptsTable_->numEntries();
     351             :         }
     352             : 
     353           0 :         IonTrackedOptimizationsAttempts trackedOptimizationAttempts(uint8_t index) {
     354           0 :             MOZ_ASSERT(hasTrackedOptimizations());
     355           0 :             return optsAttemptsTable_->entry(index);
     356             :         }
     357             : 
     358           0 :         IonTrackedOptimizationsTypeInfo trackedOptimizationTypeInfo(uint8_t index) {
     359           0 :             MOZ_ASSERT(hasTrackedOptimizations());
     360           0 :             return optsTypesTable_->entry(index);
     361             :         }
     362             : 
     363           0 :         const IonTrackedTypeVector* allTrackedTypes() {
     364           0 :             MOZ_ASSERT(hasTrackedOptimizations());
     365           0 :             return optsAllTypes_;
     366             :         }
     367             : 
     368             :         mozilla::Maybe<uint8_t> trackedOptimizationIndexAtAddr(
     369             :             JSRuntime *rt,
     370             :             void* ptr,
     371             :             uint32_t* entryOffsetOut);
     372             : 
     373             :         void forEachOptimizationAttempt(JSRuntime* rt, uint8_t index,
     374             :                                         JS::ForEachTrackedOptimizationAttemptOp& op);
     375             :         void forEachOptimizationTypeInfo(JSRuntime* rt, uint8_t index,
     376             :                                          IonTrackedOptimizationsTypeInfo::ForEachOpAdapter& op);
     377             : 
     378             :         template <class ShouldTraceProvider> bool trace(JSTracer* trc);
     379             :         void sweepChildren();
     380             :         bool isMarkedFromAnyThread(JSRuntime* rt);
     381             :     };
     382             : 
     383             :     struct BaselineEntry : public BaseEntry
     384             :     {
     385             :         JSScript* script_;
     386             :         const char* str_;
     387             : 
     388             :         // Last location that caused Ion to abort compilation and the reason
     389             :         // therein, if any. Only actionable aborts are tracked. Internal
     390             :         // errors like OOMs are not.
     391             :         jsbytecode* ionAbortPc_;
     392             :         const char* ionAbortMessage_;
     393             : 
     394         627 :         void init(JitCode* code, void* nativeStartAddr, void* nativeEndAddr,
     395             :                   JSScript* script, const char* str)
     396             :         {
     397         627 :             MOZ_ASSERT(script != nullptr);
     398         627 :             BaseEntry::init(Baseline, code, nativeStartAddr, nativeEndAddr);
     399         627 :             script_ = script;
     400         627 :             str_ = str;
     401         627 :         }
     402             : 
     403           0 :         JSScript* script() const {
     404           0 :             return script_;
     405             :         }
     406             : 
     407           0 :         const char* str() const {
     408           0 :             return str_;
     409             :         }
     410             : 
     411           0 :         void trackIonAbort(jsbytecode* pc, const char* message) {
     412           0 :             MOZ_ASSERT(script_->containsPC(pc));
     413           0 :             MOZ_ASSERT(message);
     414           0 :             ionAbortPc_ = pc;
     415           0 :             ionAbortMessage_ = message;
     416           0 :         }
     417             : 
     418             :         bool hadIonAbort() const {
     419             :             MOZ_ASSERT(!ionAbortPc_ || ionAbortMessage_);
     420             :             return ionAbortPc_ != nullptr;
     421             :         }
     422             : 
     423             :         void destroy();
     424             : 
     425             :         void* canonicalNativeAddrFor(JSRuntime* rt, void* ptr) const;
     426             : 
     427             :         MOZ_MUST_USE bool callStackAtAddr(JSRuntime* rt, void* ptr, BytecodeLocationVector& results,
     428             :                                           uint32_t* depth) const;
     429             : 
     430             :         uint32_t callStackAtAddr(JSRuntime* rt, void* ptr, const char** results,
     431             :                                  uint32_t maxResults) const;
     432             : 
     433             :         void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
     434             :                                          JSScript** script, jsbytecode** pc) const;
     435             : 
     436             :         template <class ShouldTraceProvider> bool trace(JSTracer* trc);
     437             :         void sweepChildren();
     438             :         bool isMarkedFromAnyThread(JSRuntime* rt);
     439             :     };
     440             : 
     441             :     struct IonCacheEntry : public BaseEntry
     442             :     {
     443             :         void* rejoinAddr_;
     444             :         JS::TrackedOutcome trackedOutcome_;
     445             : 
     446             :         void init(JitCode* code, void* nativeStartAddr, void* nativeEndAddr,
     447             :                   void* rejoinAddr, JS::TrackedOutcome trackedOutcome)
     448             :         {
     449             :             MOZ_ASSERT(rejoinAddr != nullptr);
     450             :             BaseEntry::init(IonCache, code, nativeStartAddr, nativeEndAddr);
     451             :             rejoinAddr_ = rejoinAddr;
     452             :             trackedOutcome_ = trackedOutcome;
     453             :         }
     454             : 
     455           0 :         void* rejoinAddr() const {
     456           0 :             return rejoinAddr_;
     457             :         }
     458             :         JS::TrackedOutcome trackedOutcome() const {
     459             :             return trackedOutcome_;
     460             :         }
     461             : 
     462           0 :         void destroy() {}
     463             : 
     464             :         void* canonicalNativeAddrFor(JSRuntime* rt, void* ptr) const;
     465             : 
     466             :         MOZ_MUST_USE bool callStackAtAddr(JSRuntime* rt, void* ptr, BytecodeLocationVector& results,
     467             :                                           uint32_t* depth) const;
     468             : 
     469             :         uint32_t callStackAtAddr(JSRuntime* rt, void* ptr, const char** results,
     470             :                                  uint32_t maxResults) const;
     471             : 
     472             :         void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
     473             :                                          JSScript** script, jsbytecode** pc) const;
     474             : 
     475           0 :         bool hasTrackedOptimizations() const { return true; }
     476             :         mozilla::Maybe<uint8_t> trackedOptimizationIndexAtAddr(
     477             :             JSRuntime *rt,
     478             :             void* ptr,
     479             :             uint32_t* entryOffsetOut);
     480             :         void forEachOptimizationAttempt(JSRuntime* rt, uint8_t index,
     481             :                                         JS::ForEachTrackedOptimizationAttemptOp& op);
     482             :         void forEachOptimizationTypeInfo(JSRuntime* rt, uint8_t index,
     483             :                                          IonTrackedOptimizationsTypeInfo::ForEachOpAdapter& op);
     484             : 
     485             :         template <class ShouldTraceProvider> bool trace(JSTracer* trc);
     486             :         void sweepChildren(JSRuntime* rt);
     487             :         bool isMarkedFromAnyThread(JSRuntime* rt);
     488             :     };
     489             : 
     490             :     // Dummy entries are created for jitcode generated when profiling is not turned on,
     491             :     // so that they have representation in the global table if they are on the
     492             :     // stack when profiling is enabled.
     493             :     struct DummyEntry : public BaseEntry
     494             :     {
     495           5 :         void init(JitCode* code, void* nativeStartAddr, void* nativeEndAddr) {
     496           5 :             BaseEntry::init(Dummy, code, nativeStartAddr, nativeEndAddr);
     497           5 :         }
     498             : 
     499           0 :         void destroy() {}
     500             : 
     501           0 :         void* canonicalNativeAddrFor(JSRuntime* rt, void* ptr) const {
     502           0 :             return nullptr;
     503             :         }
     504             : 
     505           0 :         MOZ_MUST_USE bool callStackAtAddr(JSRuntime* rt, void* ptr, BytecodeLocationVector& results,
     506             :                                           uint32_t* depth) const
     507             :         {
     508           0 :             return true;
     509             :         }
     510             : 
     511           0 :         uint32_t callStackAtAddr(JSRuntime* rt, void* ptr, const char** results,
     512             :                                  uint32_t maxResults) const
     513             :         {
     514           0 :             return 0;
     515             :         }
     516             : 
     517           0 :         void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
     518             :                                          JSScript** script, jsbytecode** pc) const
     519             :         {
     520           0 :             *script = nullptr;
     521           0 :             *pc = nullptr;
     522           0 :         }
     523             :     };
     524             : 
     525             :     // QueryEntry is never stored in the table, just used for queries
     526             :     // where an instance of JitcodeGlobalEntry is required to do tree
     527             :     // lookups.
     528             :     struct QueryEntry : public BaseEntry
     529             :     {
     530           0 :         void init(void* addr) {
     531           0 :             BaseEntry::init(Query, nullptr, addr, addr);
     532           0 :         }
     533             :         uint8_t* addr() const {
     534             :             return reinterpret_cast<uint8_t*>(nativeStartAddr());
     535             :         }
     536           0 :         void destroy() {}
     537             :     };
     538             : 
     539             :   private:
     540             :     JitcodeSkiplistTower* tower_;
     541             : 
     542             :     union {
     543             :         // Shadowing BaseEntry instance to allow access to base fields
     544             :         // and type extraction.
     545             :         BaseEntry base_;
     546             : 
     547             :         // The most common entry type: describing jitcode generated by
     548             :         // Ion main-line code.
     549             :         IonEntry ion_;
     550             : 
     551             :         // Baseline jitcode.
     552             :         BaselineEntry baseline_;
     553             : 
     554             :         // IonCache stubs.
     555             :         IonCacheEntry ionCache_;
     556             : 
     557             :         // Dummy entries.
     558             :         DummyEntry dummy_;
     559             : 
     560             :         // When doing queries on the SplayTree for particular addresses,
     561             :         // the query addresses are representd using a QueryEntry.
     562             :         QueryEntry query_;
     563             :     };
     564             : 
     565             :   public:
     566        1264 :     JitcodeGlobalEntry()
     567        1264 :       : tower_(nullptr)
     568             :     {
     569        1264 :         base_.init();
     570        1264 :     }
     571             : 
     572           0 :     explicit JitcodeGlobalEntry(const IonEntry& ion)
     573           0 :       : JitcodeGlobalEntry()
     574             :     {
     575           0 :         ion_ = ion;
     576           0 :     }
     577             : 
     578         627 :     explicit JitcodeGlobalEntry(const BaselineEntry& baseline)
     579         627 :       : JitcodeGlobalEntry()
     580             :     {
     581         627 :         baseline_ = baseline;
     582         627 :     }
     583             : 
     584             :     explicit JitcodeGlobalEntry(const IonCacheEntry& ionCache)
     585             :       : JitcodeGlobalEntry()
     586             :     {
     587             :         ionCache_ = ionCache;
     588             :     }
     589             : 
     590           5 :     explicit JitcodeGlobalEntry(const DummyEntry& dummy)
     591           5 :       : JitcodeGlobalEntry()
     592             :     {
     593           5 :         dummy_ = dummy;
     594           5 :     }
     595             : 
     596           0 :     explicit JitcodeGlobalEntry(const QueryEntry& query)
     597           0 :       : JitcodeGlobalEntry()
     598             :     {
     599           0 :         query_ = query;
     600           0 :     }
     601             : 
     602           0 :     static JitcodeGlobalEntry MakeQuery(void* ptr) {
     603             :         QueryEntry query;
     604           0 :         query.init(ptr);
     605           0 :         return JitcodeGlobalEntry(query);
     606             :     }
     607             : 
     608           0 :     void destroy() {
     609           0 :         switch (kind()) {
     610             :           case Ion:
     611           0 :             ionEntry().destroy();
     612           0 :             break;
     613             :           case Baseline:
     614           0 :             baselineEntry().destroy();
     615           0 :             break;
     616             :           case IonCache:
     617           0 :             ionCacheEntry().destroy();
     618           0 :             break;
     619             :           case Dummy:
     620           0 :             dummyEntry().destroy();
     621           0 :             break;
     622             :           case Query:
     623           0 :             queryEntry().destroy();
     624           0 :             break;
     625             :           default:
     626           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     627             :         }
     628           0 :     }
     629             : 
     630             :     JitCode* jitcode() const {
     631             :         return baseEntry().jitcode();
     632             :     }
     633       48005 :     void* nativeStartAddr() const {
     634       48005 :         return base_.nativeStartAddr();
     635             :     }
     636       24172 :     void* nativeEndAddr() const {
     637       24172 :         return base_.nativeEndAddr();
     638             :     }
     639             : 
     640             :     uint32_t generation() const {
     641             :         return baseEntry().generation();
     642             :     }
     643           0 :     void setGeneration(uint32_t gen) {
     644           0 :         baseEntry().setGeneration(gen);
     645           0 :     }
     646           0 :     void setAsExpired() {
     647           0 :         baseEntry().setGeneration(UINT32_MAX);
     648           0 :     }
     649           0 :     bool isSampled(uint32_t currentGen, uint32_t lapCount) {
     650           0 :         return baseEntry().isSampled(currentGen, lapCount);
     651             :     }
     652             : 
     653       12086 :     bool startsBelowPointer(void* ptr) const {
     654       12086 :         return base_.startsBelowPointer(ptr);
     655             :     }
     656       11747 :     bool endsAbovePointer(void* ptr) const {
     657       11747 :         return base_.endsAbovePointer(ptr);
     658             :     }
     659       24172 :     bool containsPointer(void* ptr) const {
     660       24172 :         return base_.containsPointer(ptr);
     661             :     }
     662             : 
     663       12086 :     bool overlapsWith(const JitcodeGlobalEntry& entry) const {
     664             :         // Catch full containment of |entry| within |this|, and partial overlaps.
     665       12086 :         if (containsPointer(entry.nativeStartAddr()) || containsPointer(entry.nativeEndAddr()))
     666           0 :             return true;
     667             : 
     668             :         // Catch full containment of |this| within |entry|.
     669       12086 :         if (startsBelowPointer(entry.nativeEndAddr()) && endsAbovePointer(entry.nativeStartAddr()))
     670           0 :             return true;
     671             : 
     672       12086 :         return false;
     673             :     }
     674             : 
     675       62336 :     Kind kind() const {
     676       62336 :         return base_.kind();
     677             :     }
     678             : 
     679           0 :     bool isValid() const {
     680           0 :         return (kind() > INVALID) && (kind() < LIMIT);
     681             :     }
     682        1264 :     bool isIon() const {
     683        1264 :         return kind() == Ion;
     684             :     }
     685         632 :     bool isBaseline() const {
     686         632 :         return kind() == Baseline;
     687             :     }
     688           5 :     bool isIonCache() const {
     689           5 :         return kind() == IonCache;
     690             :     }
     691           5 :     bool isDummy() const {
     692           5 :         return kind() == Dummy;
     693             :     }
     694       60430 :     bool isQuery() const {
     695       60430 :         return kind() == Query;
     696             :     }
     697             : 
     698           0 :     BaseEntry& baseEntry() {
     699           0 :         MOZ_ASSERT(isValid());
     700           0 :         return base_;
     701             :     }
     702           0 :     IonEntry& ionEntry() {
     703           0 :         MOZ_ASSERT(isIon());
     704           0 :         return ion_;
     705             :     }
     706           0 :     BaselineEntry& baselineEntry() {
     707           0 :         MOZ_ASSERT(isBaseline());
     708           0 :         return baseline_;
     709             :     }
     710           0 :     IonCacheEntry& ionCacheEntry() {
     711           0 :         MOZ_ASSERT(isIonCache());
     712           0 :         return ionCache_;
     713             :     }
     714           0 :     DummyEntry& dummyEntry() {
     715           0 :         MOZ_ASSERT(isDummy());
     716           0 :         return dummy_;
     717             :     }
     718           0 :     QueryEntry& queryEntry() {
     719           0 :         MOZ_ASSERT(isQuery());
     720           0 :         return query_;
     721             :     }
     722             : 
     723             :     const BaseEntry& baseEntry() const {
     724             :         MOZ_ASSERT(isValid());
     725             :         return base_;
     726             :     }
     727           0 :     const IonEntry& ionEntry() const {
     728           0 :         MOZ_ASSERT(isIon());
     729           0 :         return ion_;
     730             :     }
     731           0 :     const BaselineEntry& baselineEntry() const {
     732           0 :         MOZ_ASSERT(isBaseline());
     733           0 :         return baseline_;
     734             :     }
     735           0 :     const IonCacheEntry& ionCacheEntry() const {
     736           0 :         MOZ_ASSERT(isIonCache());
     737           0 :         return ionCache_;
     738             :     }
     739           0 :     const DummyEntry& dummyEntry() const {
     740           0 :         MOZ_ASSERT(isDummy());
     741           0 :         return dummy_;
     742             :     }
     743             :     const QueryEntry& queryEntry() const {
     744             :         MOZ_ASSERT(isQuery());
     745             :         return query_;
     746             :     }
     747             : 
     748           0 :     void* canonicalNativeAddrFor(JSRuntime* rt, void* ptr) const {
     749           0 :         switch (kind()) {
     750             :           case Ion:
     751           0 :             return ionEntry().canonicalNativeAddrFor(rt, ptr);
     752             :           case Baseline:
     753           0 :             return baselineEntry().canonicalNativeAddrFor(rt, ptr);
     754             :           case IonCache:
     755           0 :             return ionCacheEntry().canonicalNativeAddrFor(rt, ptr);
     756             :           case Dummy:
     757           0 :             return dummyEntry().canonicalNativeAddrFor(rt, ptr);
     758             :           default:
     759           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     760             :         }
     761             :         return nullptr;
     762             :     }
     763             : 
     764             :     // Read the inline call stack at a given point in the native code and append into
     765             :     // the given vector.  Innermost (script,pc) pair will be appended first, and
     766             :     // outermost appended last.
     767             :     //
     768             :     // Returns false on memory failure.
     769           0 :     MOZ_MUST_USE bool callStackAtAddr(JSRuntime* rt, void* ptr, BytecodeLocationVector& results,
     770             :                                       uint32_t* depth) const
     771             :     {
     772           0 :         switch (kind()) {
     773             :           case Ion:
     774           0 :             return ionEntry().callStackAtAddr(rt, ptr, results, depth);
     775             :           case Baseline:
     776           0 :             return baselineEntry().callStackAtAddr(rt, ptr, results, depth);
     777             :           case IonCache:
     778           0 :             return ionCacheEntry().callStackAtAddr(rt, ptr, results, depth);
     779             :           case Dummy:
     780           0 :             return dummyEntry().callStackAtAddr(rt, ptr, results, depth);
     781             :           default:
     782           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     783             :         }
     784             :         return false;
     785             :     }
     786             : 
     787           0 :     uint32_t callStackAtAddr(JSRuntime* rt, void* ptr, const char** results,
     788             :                              uint32_t maxResults) const
     789             :     {
     790           0 :         switch (kind()) {
     791             :           case Ion:
     792           0 :             return ionEntry().callStackAtAddr(rt, ptr, results, maxResults);
     793             :           case Baseline:
     794           0 :             return baselineEntry().callStackAtAddr(rt, ptr, results, maxResults);
     795             :           case IonCache:
     796           0 :             return ionCacheEntry().callStackAtAddr(rt, ptr, results, maxResults);
     797             :           case Dummy:
     798           0 :             return dummyEntry().callStackAtAddr(rt, ptr, results, maxResults);
     799             :           default:
     800           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     801             :         }
     802             :         return false;
     803             :     }
     804             : 
     805           0 :     void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
     806             :                                      JSScript** script, jsbytecode** pc) const
     807             :     {
     808           0 :         switch (kind()) {
     809             :           case Ion:
     810           0 :             return ionEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
     811             :           case Baseline:
     812           0 :             return baselineEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
     813             :           case IonCache:
     814           0 :             return ionCacheEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
     815             :           case Dummy:
     816           0 :             return dummyEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
     817             :           default:
     818           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     819             :         }
     820             :     }
     821             : 
     822             :     // Figure out the number of the (JSScript*, jsbytecode*) pairs that are active
     823             :     // at this location.
     824             :     uint32_t lookupInlineCallDepth(void* ptr);
     825             : 
     826             :     // Compare two global entries.
     827             :     static int compare(const JitcodeGlobalEntry& ent1, const JitcodeGlobalEntry& ent2);
     828       12086 :     int compareTo(const JitcodeGlobalEntry& other) {
     829       12086 :         return compare(*this, other);
     830             :     }
     831             : 
     832             :     // Compute a profiling string for a given script.
     833             :     static char* createScriptString(JSContext* cx, JSScript* script, size_t* length=nullptr);
     834             : 
     835           0 :     bool hasTrackedOptimizations() const {
     836           0 :         switch (kind()) {
     837             :           case Ion:
     838           0 :             return ionEntry().hasTrackedOptimizations();
     839             :           case IonCache:
     840           0 :             return ionCacheEntry().hasTrackedOptimizations();
     841             :           case Baseline:
     842             :           case Dummy:
     843           0 :             break;
     844             :           default:
     845           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     846             :         }
     847           0 :         return false;
     848             :     }
     849             : 
     850         632 :     bool canHoldNurseryPointers() const {
     851         632 :         return isIon() && ionEntry().hasTrackedOptimizations();
     852             :     }
     853             : 
     854           0 :     mozilla::Maybe<uint8_t> trackedOptimizationIndexAtAddr(
     855             :             JSRuntime *rt,
     856             :             void* addr,
     857             :             uint32_t* entryOffsetOut)
     858             :     {
     859           0 :         switch (kind()) {
     860             :           case Ion:
     861           0 :             return ionEntry().trackedOptimizationIndexAtAddr(rt, addr, entryOffsetOut);
     862             :           case IonCache:
     863           0 :             return ionCacheEntry().trackedOptimizationIndexAtAddr(rt, addr, entryOffsetOut);
     864             :           case Baseline:
     865             :           case Dummy:
     866           0 :             break;
     867             :           default:
     868           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     869             :         }
     870           0 :         return mozilla::Nothing();
     871             :     }
     872             : 
     873           0 :     void forEachOptimizationAttempt(JSRuntime* rt, uint8_t index,
     874             :                                     JS::ForEachTrackedOptimizationAttemptOp& op)
     875             :     {
     876           0 :         switch (kind()) {
     877             :           case Ion:
     878           0 :             ionEntry().forEachOptimizationAttempt(rt, index, op);
     879           0 :             return;
     880             :           case IonCache:
     881           0 :             ionCacheEntry().forEachOptimizationAttempt(rt, index, op);
     882           0 :             return;
     883             :           case Baseline:
     884             :           case Dummy:
     885           0 :             break;
     886             :           default:
     887           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     888             :         }
     889             :     }
     890             : 
     891           0 :     void forEachOptimizationTypeInfo(JSRuntime* rt, uint8_t index,
     892             :                                      IonTrackedOptimizationsTypeInfo::ForEachOpAdapter& op)
     893             :     {
     894           0 :         switch (kind()) {
     895             :           case Ion:
     896           0 :             ionEntry().forEachOptimizationTypeInfo(rt, index, op);
     897           0 :             return;
     898             :           case IonCache:
     899           0 :             ionCacheEntry().forEachOptimizationTypeInfo(rt, index, op);
     900           0 :             return;
     901             :           case Baseline:
     902             :           case Dummy:
     903           0 :             break;
     904             :           default:
     905           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     906             :         }
     907             :     }
     908             : 
     909             :     IonTrackedOptimizationsAttempts trackedOptimizationAttempts(uint8_t index) {
     910             :         return ionEntry().trackedOptimizationAttempts(index);
     911             :     }
     912             : 
     913             :     IonTrackedOptimizationsTypeInfo trackedOptimizationTypeInfo(uint8_t index) {
     914             :         return ionEntry().trackedOptimizationTypeInfo(index);
     915             :     }
     916             : 
     917             :     const IonTrackedTypeVector* allTrackedTypes() {
     918             :         return ionEntry().allTrackedTypes();
     919             :     }
     920             : 
     921           0 :     Zone* zone() {
     922           0 :         return baseEntry().jitcode()->zone();
     923             :     }
     924             : 
     925             :     template <class ShouldTraceProvider>
     926           0 :     bool trace(JSTracer* trc) {
     927           0 :         bool tracedAny = baseEntry().traceJitcode<ShouldTraceProvider>(trc);
     928           0 :         switch (kind()) {
     929             :           case Ion:
     930           0 :             tracedAny |= ionEntry().trace<ShouldTraceProvider>(trc);
     931           0 :             break;
     932             :           case Baseline:
     933           0 :             tracedAny |= baselineEntry().trace<ShouldTraceProvider>(trc);
     934           0 :             break;
     935             :           case IonCache:
     936           0 :             tracedAny |= ionCacheEntry().trace<ShouldTraceProvider>(trc);
     937           0 :             break;
     938             :           case Dummy:
     939           0 :             break;
     940             :           default:
     941           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     942             :         }
     943           0 :         return tracedAny;
     944             :     }
     945             : 
     946           0 :     void sweepChildren(JSRuntime* rt) {
     947           0 :         switch (kind()) {
     948             :           case Ion:
     949           0 :             ionEntry().sweepChildren();
     950           0 :             break;
     951             :           case Baseline:
     952           0 :             baselineEntry().sweepChildren();
     953           0 :             break;
     954             :           case IonCache:
     955           0 :             ionCacheEntry().sweepChildren(rt);
     956           0 :             break;
     957             :           case Dummy:
     958           0 :             break;
     959             :           default:
     960           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     961             :         }
     962           0 :     }
     963             : 
     964           0 :     bool isMarkedFromAnyThread(JSRuntime* rt) {
     965           0 :         if (!baseEntry().isJitcodeMarkedFromAnyThread(rt))
     966           0 :             return false;
     967           0 :         switch (kind()) {
     968             :           case Ion:
     969           0 :             return ionEntry().isMarkedFromAnyThread(rt);
     970             :           case Baseline:
     971           0 :             return baselineEntry().isMarkedFromAnyThread(rt);
     972             :           case IonCache:
     973           0 :             return ionCacheEntry().isMarkedFromAnyThread(rt);
     974             :           case Dummy:
     975           0 :             break;
     976             :           default:
     977           0 :             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
     978             :         }
     979           0 :         return true;
     980             :     }
     981             : 
     982             :     //
     983             :     // When stored in a free-list, entries use 'tower_' to store a
     984             :     // pointer to the next entry.  In this context only, 'tower_'
     985             :     // may refer to a |JitcodeGlobalEntry*| instead of a
     986             :     // |JitcodeSkiplistTower*|.
     987             :     //
     988             : 
     989           0 :     void addToFreeList(JitcodeGlobalEntry** freeList) {
     990           0 :         MOZ_ASSERT(!isValid());
     991             : 
     992           0 :         JitcodeGlobalEntry* nextFreeEntry = *freeList;
     993           0 :         MOZ_ASSERT_IF(nextFreeEntry, !nextFreeEntry->isValid());
     994             : 
     995           0 :         tower_ = (JitcodeSkiplistTower*) nextFreeEntry;
     996           0 :         *freeList = this;
     997           0 :     }
     998             : 
     999         632 :     static JitcodeGlobalEntry* PopFromFreeList(JitcodeGlobalEntry** freeList) {
    1000         632 :         if (!*freeList)
    1001         632 :             return nullptr;
    1002             : 
    1003           0 :         JitcodeGlobalEntry* entry = *freeList;
    1004           0 :         MOZ_ASSERT(!entry->isValid());
    1005           0 :         JitcodeGlobalEntry* nextFreeEntry = (JitcodeGlobalEntry*) entry->tower_;
    1006           0 :         entry->tower_ = nullptr;
    1007           0 :         *freeList = nextFreeEntry;
    1008           0 :         return entry;
    1009             :     }
    1010             : };
    1011             : 
    1012             : /*
    1013             :  * Global table of JitcodeGlobalEntry values sorted by native address range.
    1014             :  */
    1015             : class JitcodeGlobalTable
    1016             : {
    1017             :   private:
    1018             :     static const size_t LIFO_CHUNK_SIZE = 16 * 1024;
    1019             : 
    1020             :     LifoAlloc alloc_;
    1021             :     JitcodeGlobalEntry* freeEntries_;
    1022             :     uint32_t rand_;
    1023             :     uint32_t skiplistSize_;
    1024             :     JitcodeGlobalEntry::IonEntry* nurseryEntries_;
    1025             : 
    1026             :     JitcodeGlobalEntry* startTower_[JitcodeSkiplistTower::MAX_HEIGHT];
    1027             :     JitcodeSkiplistTower* freeTowers_[JitcodeSkiplistTower::MAX_HEIGHT];
    1028             : 
    1029             :   public:
    1030           4 :     JitcodeGlobalTable()
    1031           4 :       : alloc_(LIFO_CHUNK_SIZE), freeEntries_(nullptr), rand_(0), skiplistSize_(0),
    1032           4 :         nurseryEntries_(nullptr)
    1033             :     {
    1034         132 :         for (unsigned i = 0; i < JitcodeSkiplistTower::MAX_HEIGHT; i++)
    1035         128 :             startTower_[i] = nullptr;
    1036         132 :         for (unsigned i = 0; i < JitcodeSkiplistTower::MAX_HEIGHT; i++)
    1037         128 :             freeTowers_[i] = nullptr;
    1038           4 :     }
    1039           0 :     ~JitcodeGlobalTable() {}
    1040             : 
    1041           0 :     bool empty() const {
    1042           0 :         return skiplistSize_ == 0;
    1043             :     }
    1044             : 
    1045           0 :     const JitcodeGlobalEntry* lookup(void* ptr) {
    1046           0 :         return lookupInternal(ptr);
    1047             :     }
    1048             : 
    1049           0 :     JitcodeGlobalEntry& lookupInfallible(void* ptr) {
    1050           0 :         JitcodeGlobalEntry* entry = lookupInternal(ptr);
    1051           0 :         MOZ_ASSERT(entry);
    1052           0 :         return *entry;
    1053             :     }
    1054             : 
    1055             :     const JitcodeGlobalEntry& lookupForSamplerInfallible(void* ptr, JSRuntime* rt,
    1056             :                                                          uint32_t sampleBufferGen);
    1057             : 
    1058           0 :     MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::IonEntry& entry, JSRuntime* rt) {
    1059           0 :         return addEntry(JitcodeGlobalEntry(entry), rt);
    1060             :     }
    1061         627 :     MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::BaselineEntry& entry, JSRuntime* rt) {
    1062         627 :         return addEntry(JitcodeGlobalEntry(entry), rt);
    1063             :     }
    1064             :     MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::IonCacheEntry& entry, JSRuntime* rt) {
    1065             :         return addEntry(JitcodeGlobalEntry(entry), rt);
    1066             :     }
    1067           5 :     MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::DummyEntry& entry, JSRuntime* rt) {
    1068           5 :         return addEntry(JitcodeGlobalEntry(entry), rt);
    1069             :     }
    1070             : 
    1071             :     void removeEntry(JitcodeGlobalEntry& entry, JitcodeGlobalEntry** prevTower, JSRuntime* rt);
    1072             :     void releaseEntry(JitcodeGlobalEntry& entry, JitcodeGlobalEntry** prevTower, JSRuntime* rt);
    1073             : 
    1074             :     void setAllEntriesAsExpired(JSRuntime* rt);
    1075             :     void traceForMinorGC(JSTracer* trc);
    1076             :     MOZ_MUST_USE bool markIteratively(GCMarker* marker);
    1077             :     void sweep(JSRuntime* rt);
    1078             : 
    1079             :   private:
    1080             :     MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry& entry, JSRuntime* rt);
    1081             : 
    1082             :     JitcodeGlobalEntry* lookupInternal(void* ptr);
    1083             : 
    1084             :     // Initialize towerOut such that towerOut[i] (for i in [0, MAX_HEIGHT-1])
    1085             :     // is a JitcodeGlobalEntry that is sorted to be <query, whose successor at
    1086             :     // level i is either null, or sorted to be >= query.
    1087             :     //
    1088             :     // If entry with the given properties does not exist for level i, then
    1089             :     // towerOut[i] is initialized to nullptr.
    1090             :     void searchInternal(const JitcodeGlobalEntry& query, JitcodeGlobalEntry** towerOut);
    1091             : 
    1092             :     JitcodeGlobalEntry* searchAtHeight(unsigned level, JitcodeGlobalEntry* start,
    1093             :                                        const JitcodeGlobalEntry& query);
    1094             : 
    1095             :     // Calculate next random tower height.
    1096             :     unsigned generateTowerHeight();
    1097             : 
    1098             :     JitcodeSkiplistTower* allocateTower(unsigned height);
    1099             :     JitcodeGlobalEntry* allocateEntry();
    1100             : 
    1101             : #ifdef DEBUG
    1102             :     void verifySkiplist();
    1103             : #else
    1104             :     void verifySkiplist() {}
    1105             : #endif
    1106             : 
    1107           0 :     void addToNurseryList(JitcodeGlobalEntry::IonEntry* entry) {
    1108           0 :         MOZ_ASSERT(entry->prevNursery_ == nullptr);
    1109           0 :         MOZ_ASSERT(entry->nextNursery_ == nullptr);
    1110             : 
    1111           0 :         entry->nextNursery_ = nurseryEntries_;
    1112           0 :         if (nurseryEntries_)
    1113           0 :             nurseryEntries_->prevNursery_ = entry;
    1114           0 :         nurseryEntries_ = entry;
    1115           0 :     }
    1116             : 
    1117           0 :     void removeFromNurseryList(JitcodeGlobalEntry::IonEntry* entry) {
    1118             :         // Splice out of list to be scanned on a minor GC.
    1119           0 :         if (entry->prevNursery_)
    1120           0 :             entry->prevNursery_->nextNursery_ = entry->nextNursery_;
    1121           0 :         if (entry->nextNursery_)
    1122           0 :             entry->nextNursery_->prevNursery_ = entry->prevNursery_;
    1123             : 
    1124           0 :         if (nurseryEntries_ == entry)
    1125           0 :             nurseryEntries_ = entry->nextNursery_;
    1126             : 
    1127           0 :         entry->prevNursery_ = entry->nextNursery_ = nullptr;
    1128           0 :     }
    1129             : 
    1130             :   public:
    1131             :     class Range
    1132             :     {
    1133             :       protected:
    1134             :         JitcodeGlobalTable& table_;
    1135             :         JitcodeGlobalEntry* cur_;
    1136             : 
    1137             :       public:
    1138           0 :         explicit Range(JitcodeGlobalTable& table)
    1139           0 :           : table_(table),
    1140           0 :             cur_(table.startTower_[0])
    1141           0 :         { }
    1142             : 
    1143           0 :         JitcodeGlobalEntry* front() const {
    1144           0 :             MOZ_ASSERT(!empty());
    1145           0 :             return cur_;
    1146             :         }
    1147             : 
    1148           0 :         bool empty() const {
    1149           0 :             return !cur_;
    1150             :         }
    1151             : 
    1152           0 :         void popFront() {
    1153           0 :             MOZ_ASSERT(!empty());
    1154           0 :             cur_ = cur_->tower_->next(0);
    1155           0 :         }
    1156             :     };
    1157             : 
    1158             :     // An enumerator class that can remove entries as it enumerates. If this
    1159             :     // functionality is not needed, use Range instead.
    1160             :     class Enum : public Range
    1161             :     {
    1162             :         JSRuntime* rt_;
    1163             :         JitcodeGlobalEntry* next_;
    1164             :         JitcodeGlobalEntry* prevTower_[JitcodeSkiplistTower::MAX_HEIGHT];
    1165             : 
    1166             :       public:
    1167             :         Enum(JitcodeGlobalTable& table, JSRuntime* rt);
    1168             : 
    1169             :         void popFront();
    1170             :         void removeFront();
    1171             :     };
    1172             : };
    1173             : 
    1174             : 
    1175             : /*
    1176             :  * Container class for main jitcode table.
    1177             :  * The Region table's memory is structured as follows:
    1178             :  *
    1179             :  *      +------------------------------------------------+   |
    1180             :  *      |  Region 1 Run                                  |   |
    1181             :  *      |------------------------------------------------|   |
    1182             :  *      |  Region 2 Run                                  |   |
    1183             :  *      |                                                |   |
    1184             :  *      |                                                |   |
    1185             :  *      |------------------------------------------------|   |
    1186             :  *      |  Region 3 Run                                  |   |
    1187             :  *      |                                                |   |
    1188             :  *      |------------------------------------------------|   |-- Payload
    1189             :  *      |                                                |   |
    1190             :  *      |               ...                              |   |
    1191             :  *      |                                                |   |
    1192             :  *      |------------------------------------------------|   |
    1193             :  *      |  Region M Run                                  |   |
    1194             :  *      |                                                |   |
    1195             :  *      +================================================+ <- RegionTable pointer points here
    1196             :  *      | uint23_t numRegions = M                        |   |
    1197             :  *      +------------------------------------------------+   |
    1198             :  *      | Region 1                                       |   |
    1199             :  *      |   uint32_t entryOffset = size(Payload)         |   |
    1200             :  *      +------------------------------------------------+   |
    1201             :  *      |                                                |   |-- Table
    1202             :  *      |   ...                                          |   |
    1203             :  *      |                                                |   |
    1204             :  *      +------------------------------------------------+   |
    1205             :  *      | Region M                                       |   |
    1206             :  *      |   uint32_t entryOffset                         |   |
    1207             :  *      +------------------------------------------------+   |
    1208             :  *
    1209             :  * The region table is composed of two sections: a tail section that contains a table of
    1210             :  * fixed-size entries containing offsets into the the head section, and a head section that
    1211             :  * holds a sequence of variable-sized runs.  The table in the tail section serves to
    1212             :  * locate the variable-length encoded structures in the head section.
    1213             :  *
    1214             :  * The entryOffsets in the table indicate the bytes offset to subtract from the regionTable
    1215             :  * pointer to arrive at the encoded region in the payload.
    1216             :  *
    1217             :  *
    1218             :  * Variable-length entries in payload
    1219             :  * ----------------------------------
    1220             :  * The entryOffsets in the region table's fixed-sized entries refer to a location within the
    1221             :  * variable-length payload section.  This location contains a compactly encoded "run" of
    1222             :  * mappings.
    1223             :  *
    1224             :  * Each run starts by describing the offset within the native code it starts at, and the
    1225             :  * sequence of (JSScript*, jsbytecode*) pairs active at that site.  Following that, there
    1226             :  * are a number of variable-length entries encoding (nativeOffsetDelta, bytecodeOffsetDelta)
    1227             :  * pairs for the run.
    1228             :  *
    1229             :  *      VarUint32 nativeOffset;
    1230             :  *          - The offset from nativeStartAddr in the global table entry at which
    1231             :  *            the jitcode for this region starts.
    1232             :  *
    1233             :  *      Uint8_t scriptDepth;
    1234             :  *          - The depth of inlined scripts for this region.
    1235             :  *
    1236             :  *      List<VarUint32> inlineScriptPcStack;
    1237             :  *          - We encode (2 * scriptDepth) VarUint32s here.  Each pair of uint32s are taken
    1238             :  *            as an index into the scriptList in the global table entry, and a pcOffset
    1239             :  *            respectively.
    1240             :  *
    1241             :  *      List<NativeAndBytecodeDelta> deltaRun;
    1242             :  *          - The rest of the entry is a deltaRun that stores a series of variable-length
    1243             :  *            encoded NativeAndBytecodeDelta datums.
    1244             :  */
    1245             : class JitcodeRegionEntry
    1246             : {
    1247             :   private:
    1248             :     static const unsigned MAX_RUN_LENGTH = 100;
    1249             : 
    1250             :   public:
    1251             :     static void WriteHead(CompactBufferWriter& writer,
    1252             :                           uint32_t nativeOffset, uint8_t scriptDepth);
    1253             :     static void ReadHead(CompactBufferReader& reader,
    1254             :                          uint32_t* nativeOffset, uint8_t* scriptDepth);
    1255             : 
    1256             :     static void WriteScriptPc(CompactBufferWriter& writer, uint32_t scriptIdx, uint32_t pcOffset);
    1257             :     static void ReadScriptPc(CompactBufferReader& reader, uint32_t* scriptIdx, uint32_t* pcOffset);
    1258             : 
    1259             :     static void WriteDelta(CompactBufferWriter& writer, uint32_t nativeDelta, int32_t pcDelta);
    1260             :     static void ReadDelta(CompactBufferReader& reader, uint32_t* nativeDelta, int32_t* pcDelta);
    1261             : 
    1262             :     // Given a pointer into an array of NativeToBytecode (and a pointer to the end of the array),
    1263             :     // compute the number of entries that would be consume by outputting a run starting
    1264             :     // at this one.
    1265             :     static uint32_t ExpectedRunLength(const CodeGeneratorShared::NativeToBytecode* entry,
    1266             :                                       const CodeGeneratorShared::NativeToBytecode* end);
    1267             : 
    1268             :     // Write a run, starting at the given NativeToBytecode entry, into the given buffer writer.
    1269             :     static MOZ_MUST_USE bool WriteRun(CompactBufferWriter& writer, JSScript** scriptList,
    1270             :                                       uint32_t scriptListSize, uint32_t runLength,
    1271             :                                       const CodeGeneratorShared::NativeToBytecode* entry);
    1272             : 
    1273             :     // Delta Run entry formats are encoded little-endian:
    1274             :     //
    1275             :     //  byte 0
    1276             :     //  NNNN-BBB0
    1277             :     //      Single byte format.  nativeDelta in [0, 15], pcDelta in [0, 7]
    1278             :     //
    1279             :     static const uint32_t ENC1_MASK = 0x1;
    1280             :     static const uint32_t ENC1_MASK_VAL = 0x0;
    1281             : 
    1282             :     static const uint32_t ENC1_NATIVE_DELTA_MAX = 0xf;
    1283             :     static const unsigned ENC1_NATIVE_DELTA_SHIFT = 4;
    1284             : 
    1285             :     static const uint32_t ENC1_PC_DELTA_MASK = 0x0e;
    1286             :     static const int32_t ENC1_PC_DELTA_MAX = 0x7;
    1287             :     static const unsigned ENC1_PC_DELTA_SHIFT = 1;
    1288             : 
    1289             :     //  byte 1    byte 0
    1290             :     //  NNNN-NNNN BBBB-BB01
    1291             :     //      Two-byte format.  nativeDelta in [0, 255], pcDelta in [0, 63]
    1292             :     //
    1293             :     static const uint32_t ENC2_MASK = 0x3;
    1294             :     static const uint32_t ENC2_MASK_VAL = 0x1;
    1295             : 
    1296             :     static const uint32_t ENC2_NATIVE_DELTA_MAX = 0xff;
    1297             :     static const unsigned ENC2_NATIVE_DELTA_SHIFT = 8;
    1298             : 
    1299             :     static const uint32_t ENC2_PC_DELTA_MASK = 0x00fc;
    1300             :     static const int32_t ENC2_PC_DELTA_MAX = 0x3f;
    1301             :     static const unsigned ENC2_PC_DELTA_SHIFT = 2;
    1302             : 
    1303             :     //  byte 2    byte 1    byte 0
    1304             :     //  NNNN-NNNN NNNB-BBBB BBBB-B011
    1305             :     //      Three-byte format.  nativeDelta in [0, 2047], pcDelta in [-512, 511]
    1306             :     //
    1307             :     static const uint32_t ENC3_MASK = 0x7;
    1308             :     static const uint32_t ENC3_MASK_VAL = 0x3;
    1309             : 
    1310             :     static const uint32_t ENC3_NATIVE_DELTA_MAX = 0x7ff;
    1311             :     static const unsigned ENC3_NATIVE_DELTA_SHIFT = 13;
    1312             : 
    1313             :     static const uint32_t ENC3_PC_DELTA_MASK = 0x001ff8;
    1314             :     static const int32_t ENC3_PC_DELTA_MAX = 0x1ff;
    1315             :     static const int32_t ENC3_PC_DELTA_MIN = -ENC3_PC_DELTA_MAX - 1;
    1316             :     static const unsigned ENC3_PC_DELTA_SHIFT = 3;
    1317             : 
    1318             :     //  byte 3    byte 2    byte 1    byte 0
    1319             :     //  NNNN-NNNN NNNN-NNNN BBBB-BBBB BBBB-B111
    1320             :     //      Three-byte format.  nativeDelta in [0, 65535], pcDelta in [-4096, 4095]
    1321             :     static const uint32_t ENC4_MASK = 0x7;
    1322             :     static const uint32_t ENC4_MASK_VAL = 0x7;
    1323             : 
    1324             :     static const uint32_t ENC4_NATIVE_DELTA_MAX = 0xffff;
    1325             :     static const unsigned ENC4_NATIVE_DELTA_SHIFT = 16;
    1326             : 
    1327             :     static const uint32_t ENC4_PC_DELTA_MASK = 0x0000fff8;
    1328             :     static const int32_t ENC4_PC_DELTA_MAX = 0xfff;
    1329             :     static const int32_t ENC4_PC_DELTA_MIN = -ENC4_PC_DELTA_MAX - 1;
    1330             :     static const unsigned ENC4_PC_DELTA_SHIFT = 3;
    1331             : 
    1332           0 :     static bool IsDeltaEncodeable(uint32_t nativeDelta, int32_t pcDelta) {
    1333           0 :         return (nativeDelta <= ENC4_NATIVE_DELTA_MAX) &&
    1334           0 :                (pcDelta >= ENC4_PC_DELTA_MIN) && (pcDelta <= ENC4_PC_DELTA_MAX);
    1335             :     }
    1336             : 
    1337             :   private:
    1338             :     const uint8_t* data_;
    1339             :     const uint8_t* end_;
    1340             : 
    1341             :     // Unpacked state from jitcode entry.
    1342             :     uint32_t nativeOffset_;
    1343             :     uint8_t scriptDepth_;
    1344             :     const uint8_t* scriptPcStack_;
    1345             :     const uint8_t* deltaRun_;
    1346             : 
    1347             :     void unpack();
    1348             : 
    1349             :   public:
    1350           0 :     JitcodeRegionEntry(const uint8_t* data, const uint8_t* end)
    1351           0 :       : data_(data), end_(end),
    1352             :         nativeOffset_(0), scriptDepth_(0),
    1353           0 :         scriptPcStack_(nullptr), deltaRun_(nullptr)
    1354             :     {
    1355           0 :         MOZ_ASSERT(data_ < end_);
    1356           0 :         unpack();
    1357           0 :         MOZ_ASSERT(scriptPcStack_ < end_);
    1358           0 :         MOZ_ASSERT(deltaRun_ <= end_);
    1359           0 :     }
    1360             : 
    1361           0 :     uint32_t nativeOffset() const {
    1362           0 :         return nativeOffset_;
    1363             :     }
    1364           0 :     uint32_t scriptDepth() const {
    1365           0 :         return scriptDepth_;
    1366             :     }
    1367             : 
    1368             :     class ScriptPcIterator
    1369             :     {
    1370             :       private:
    1371             :         uint32_t count_;
    1372             :         const uint8_t* start_;
    1373             :         const uint8_t* end_;
    1374             : 
    1375             :         uint32_t idx_;
    1376             :         const uint8_t* cur_;
    1377             : 
    1378             :       public:
    1379           0 :         ScriptPcIterator(uint32_t count, const uint8_t* start, const uint8_t* end)
    1380           0 :           : count_(count), start_(start), end_(end), idx_(0), cur_(start_)
    1381           0 :         {}
    1382             : 
    1383           0 :         bool hasMore() const
    1384             :         {
    1385           0 :             MOZ_ASSERT((idx_ == count_) == (cur_ == end_));
    1386           0 :             MOZ_ASSERT((idx_ < count_) == (cur_ < end_));
    1387           0 :             return cur_ < end_;
    1388             :         }
    1389             : 
    1390           0 :         void readNext(uint32_t* scriptIdxOut, uint32_t* pcOffsetOut)
    1391             :         {
    1392           0 :             MOZ_ASSERT(scriptIdxOut);
    1393           0 :             MOZ_ASSERT(pcOffsetOut);
    1394           0 :             MOZ_ASSERT(hasMore());
    1395             : 
    1396           0 :             CompactBufferReader reader(cur_, end_);
    1397           0 :             ReadScriptPc(reader, scriptIdxOut, pcOffsetOut);
    1398             : 
    1399           0 :             cur_ = reader.currentPosition();
    1400           0 :             MOZ_ASSERT(cur_ <= end_);
    1401             : 
    1402           0 :             idx_++;
    1403           0 :             MOZ_ASSERT_IF(idx_ == count_, cur_ == end_);
    1404           0 :         }
    1405             : 
    1406           0 :         void reset() {
    1407           0 :             idx_ = 0;
    1408           0 :             cur_ = start_;
    1409           0 :         }
    1410             :     };
    1411             : 
    1412           0 :     ScriptPcIterator scriptPcIterator() const {
    1413             :         // End of script+pc sequence is the start of the delta run.
    1414           0 :         return ScriptPcIterator(scriptDepth_, scriptPcStack_,  deltaRun_);
    1415             :     }
    1416             : 
    1417             :     class DeltaIterator {
    1418             :       private:
    1419             :         const uint8_t* start_;
    1420             :         const uint8_t* end_;
    1421             :         const uint8_t* cur_;
    1422             : 
    1423             :       public:
    1424           0 :         DeltaIterator(const uint8_t* start, const uint8_t* end)
    1425           0 :           : start_(start), end_(end), cur_(start)
    1426           0 :         {}
    1427             : 
    1428           0 :         bool hasMore() const
    1429             :         {
    1430           0 :             MOZ_ASSERT(cur_ <= end_);
    1431           0 :             return cur_ < end_;
    1432             :         }
    1433             : 
    1434           0 :         void readNext(uint32_t* nativeDeltaOut, int32_t* pcDeltaOut)
    1435             :         {
    1436           0 :             MOZ_ASSERT(nativeDeltaOut != nullptr);
    1437           0 :             MOZ_ASSERT(pcDeltaOut != nullptr);
    1438             : 
    1439           0 :             MOZ_ASSERT(hasMore());
    1440             : 
    1441           0 :             CompactBufferReader reader(cur_, end_);
    1442           0 :             ReadDelta(reader, nativeDeltaOut, pcDeltaOut);
    1443             : 
    1444           0 :             cur_ = reader.currentPosition();
    1445           0 :             MOZ_ASSERT(cur_ <= end_);
    1446           0 :         }
    1447             : 
    1448             :         void reset() {
    1449             :             cur_ = start_;
    1450             :         }
    1451             :     };
    1452           0 :     DeltaIterator deltaIterator() const {
    1453           0 :         return DeltaIterator(deltaRun_, end_);
    1454             :     }
    1455             : 
    1456             :     uint32_t findPcOffset(uint32_t queryNativeOffset, uint32_t startPcOffset) const;
    1457             : };
    1458             : 
    1459             : class JitcodeIonTable
    1460             : {
    1461             :   private:
    1462             :     /* Variable length payload section "below" here. */
    1463             :     uint32_t numRegions_;
    1464             :     uint32_t regionOffsets_[1];
    1465             : 
    1466           0 :     const uint8_t* payloadEnd() const {
    1467           0 :         return reinterpret_cast<const uint8_t*>(this);
    1468             :     }
    1469             : 
    1470             :   public:
    1471             :     explicit JitcodeIonTable(uint32_t numRegions)
    1472             :       : numRegions_(numRegions)
    1473             :     {
    1474             :         for (uint32_t i = 0; i < numRegions; i++)
    1475             :             regionOffsets_[i] = 0;
    1476             :     }
    1477             : 
    1478             :     MOZ_MUST_USE bool makeIonEntry(JSContext* cx, JitCode* code, uint32_t numScripts,
    1479             :                                    JSScript** scripts, JitcodeGlobalEntry::IonEntry& out);
    1480             : 
    1481           0 :     uint32_t numRegions() const {
    1482           0 :         return numRegions_;
    1483             :     }
    1484             : 
    1485           0 :     uint32_t regionOffset(uint32_t regionIndex) const {
    1486           0 :         MOZ_ASSERT(regionIndex < numRegions());
    1487           0 :         return regionOffsets_[regionIndex];
    1488             :     }
    1489             : 
    1490           0 :     JitcodeRegionEntry regionEntry(uint32_t regionIndex) const {
    1491           0 :         const uint8_t* regionStart = payloadEnd() - regionOffset(regionIndex);
    1492           0 :         const uint8_t* regionEnd = payloadEnd();
    1493           0 :         if (regionIndex < numRegions_ - 1)
    1494           0 :             regionEnd -= regionOffset(regionIndex + 1);
    1495           0 :         return JitcodeRegionEntry(regionStart, regionEnd);
    1496             :     }
    1497             : 
    1498             :     bool regionContainsOffset(uint32_t regionIndex, uint32_t nativeOffset) {
    1499             :         MOZ_ASSERT(regionIndex < numRegions());
    1500             : 
    1501             :         JitcodeRegionEntry ent = regionEntry(regionIndex);
    1502             :         if (nativeOffset < ent.nativeOffset())
    1503             :             return false;
    1504             : 
    1505             :         if (regionIndex == numRegions_ - 1)
    1506             :             return true;
    1507             : 
    1508             :         return nativeOffset < regionEntry(regionIndex + 1).nativeOffset();
    1509             :     }
    1510             : 
    1511             :     uint32_t findRegionEntry(uint32_t offset) const;
    1512             : 
    1513           0 :     const uint8_t* payloadStart() const {
    1514             :         // The beginning of the payload the beginning of the first region are the same.
    1515           0 :         return payloadEnd() - regionOffset(0);
    1516             :     }
    1517             : 
    1518             :     static MOZ_MUST_USE bool WriteIonTable(CompactBufferWriter& writer,
    1519             :                                            JSScript** scriptList, uint32_t scriptListSize,
    1520             :                                            const CodeGeneratorShared::NativeToBytecode* start,
    1521             :                                            const CodeGeneratorShared::NativeToBytecode* end,
    1522             :                                            uint32_t* tableOffsetOut, uint32_t* numRegionsOut);
    1523             : };
    1524             : 
    1525             : 
    1526             : } // namespace jit
    1527             : } // namespace js
    1528             : 
    1529             : #endif /* jit_JitcodeMap_h */

Generated by: LCOV version 1.13