LCOV - code coverage report
Current view: top level - js/src/frontend - NameCollections.h (source / functions) Hit Total Coverage
Test: output.info Lines: 96 102 94.1 %
Date: 2017-07-14 16:53:18 Functions: 85 99 85.9 %
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 frontend_NameCollections_h
       8             : #define frontend_NameCollections_h
       9             : 
      10             : #include "ds/InlineTable.h"
      11             : #include "frontend/NameAnalysisTypes.h"
      12             : #include "js/Vector.h"
      13             : #include "vm/Stack.h"
      14             : 
      15             : namespace js {
      16             : namespace frontend {
      17             : 
      18             : // A pool of recyclable containers for use in the frontend. The Parser and
      19             : // BytecodeEmitter create many maps for name analysis that are short-lived
      20             : // (i.e., for the duration of parsing or emitting a lexical scope). Making
      21             : // them recyclable cuts down significantly on allocator churn.
      22             : template <typename RepresentativeCollection, typename ConcreteCollectionPool>
      23          80 : class CollectionPool
      24             : {
      25             :     using RecyclableCollections = Vector<void*, 32, SystemAllocPolicy>;
      26             : 
      27             :     RecyclableCollections all_;
      28             :     RecyclableCollections recyclable_;
      29             : 
      30       57150 :     static RepresentativeCollection* asRepresentative(void* p) {
      31       57150 :         return reinterpret_cast<RepresentativeCollection*>(p);
      32             :     }
      33             : 
      34         129 :     RepresentativeCollection* allocate() {
      35         129 :         size_t newAllLength = all_.length() + 1;
      36         129 :         if (!all_.reserve(newAllLength) || !recyclable_.reserve(newAllLength))
      37           0 :             return nullptr;
      38             : 
      39         129 :         RepresentativeCollection* collection = js_new<RepresentativeCollection>();
      40         129 :         if (collection)
      41         129 :             all_.infallibleAppend(collection);
      42         129 :         return collection;
      43             :     }
      44             : 
      45             :   public:
      46           0 :     ~CollectionPool() {
      47           0 :         purgeAll();
      48           0 :     }
      49             : 
      50             :     bool empty() const {
      51             :         return all_.empty();
      52             :     }
      53             : 
      54           2 :     void purgeAll() {
      55           2 :         void** end = all_.end();
      56          36 :         for (void** it = all_.begin(); it != end; ++it)
      57          34 :             js_delete(asRepresentative(*it));
      58             : 
      59           2 :         all_.clearAndFree();
      60           2 :         recyclable_.clearAndFree();
      61           2 :     }
      62             : 
      63             :     // Fallibly aquire one of the supported collection types from the pool.
      64             :     template <typename Collection>
      65       57189 :     Collection* acquire(JSContext* cx) {
      66       57189 :         ConcreteCollectionPool::template assertInvariants<Collection>();
      67             : 
      68             :         RepresentativeCollection* collection;
      69       57189 :         if (recyclable_.empty()) {
      70         129 :             collection = allocate();
      71         129 :             if (!collection)
      72           0 :                 ReportOutOfMemory(cx);
      73             :         } else {
      74       57060 :             collection = asRepresentative(recyclable_.popCopy());
      75       57060 :             collection->clear();
      76             :         }
      77       57189 :         return reinterpret_cast<Collection*>(collection);
      78             :     }
      79             : 
      80             :     // Release a collection back to the pool.
      81             :     template <typename Collection>
      82       57194 :     void release(Collection** collection) {
      83       57194 :         ConcreteCollectionPool::template assertInvariants<Collection>();
      84       57194 :         MOZ_ASSERT(*collection);
      85             : 
      86             : #ifdef DEBUG
      87       57194 :         bool ok = false;
      88             :         // Make sure the collection is in |all_| but not already in |recyclable_|.
      89      281026 :         for (void** it = all_.begin(); it != all_.end(); ++it) {
      90      281026 :             if (*it == *collection) {
      91       57194 :                 ok = true;
      92       57194 :                 break;
      93             :             }
      94             :         }
      95       57194 :         MOZ_ASSERT(ok);
      96      751149 :         for (void** it = recyclable_.begin(); it != recyclable_.end(); ++it)
      97      693955 :             MOZ_ASSERT(*it != *collection);
      98             : #endif
      99             : 
     100       57194 :         MOZ_ASSERT(recyclable_.length() < all_.length());
     101             :         // Reserved in allocateFresh.
     102       57194 :         recyclable_.infallibleAppend(*collection);
     103       57194 :         *collection = nullptr;
     104       57194 :     }
     105             : };
     106             : 
     107             : template <typename Wrapped>
     108             : struct RecyclableAtomMapValueWrapper
     109             : {
     110             :     union {
     111             :         Wrapped wrapped;
     112             :         uint64_t dummy;
     113             :     };
     114             : 
     115      141353 :     static void assertInvariant() {
     116             :         static_assert(sizeof(Wrapped) <= sizeof(uint64_t),
     117             :                       "Can only recycle atom maps with values smaller than uint64");
     118      141353 :     }
     119             : 
     120        2112 :     RecyclableAtomMapValueWrapper() {
     121        2112 :         assertInvariant();
     122        2112 :     }
     123             : 
     124      139241 :     MOZ_IMPLICIT RecyclableAtomMapValueWrapper(Wrapped w)
     125      139241 :       : wrapped(w)
     126             :     {
     127      139241 :         assertInvariant();
     128      139241 :     }
     129             : 
     130       82255 :     MOZ_IMPLICIT operator Wrapped&() {
     131       82255 :         return wrapped;
     132             :     }
     133             : 
     134             :     MOZ_IMPLICIT operator Wrapped&() const {
     135             :         return wrapped;
     136             :     }
     137             : 
     138       99275 :     Wrapped* operator->() {
     139       99275 :         return &wrapped;
     140             :     }
     141             : 
     142             :     const Wrapped* operator->() const {
     143             :         return &wrapped;
     144             :     }
     145             : };
     146             : 
     147             : template <typename MapValue>
     148             : using RecyclableNameMap = InlineMap<JSAtom*,
     149             :                                     RecyclableAtomMapValueWrapper<MapValue>,
     150             :                                     24,
     151             :                                     DefaultHasher<JSAtom*>,
     152             :                                     SystemAllocPolicy>;
     153             : 
     154             : using DeclaredNameMap = RecyclableNameMap<DeclaredNameInfo>;
     155             : using CheckTDZMap = RecyclableNameMap<MaybeCheckTDZ>;
     156             : using NameLocationMap = RecyclableNameMap<NameLocation>;
     157             : using AtomIndexMap = RecyclableNameMap<uint32_t>;
     158             : 
     159             : #undef RECYCLABLE_NAME_MAP_TYPE
     160             : 
     161             : template <typename RepresentativeTable>
     162          40 : class InlineTablePool
     163             :   : public CollectionPool<RepresentativeTable, InlineTablePool<RepresentativeTable>>
     164             : {
     165             :   public:
     166             :     template <typename Table>
     167       84355 :     static void assertInvariants() {
     168             :         static_assert(Table::SizeOfInlineEntries == RepresentativeTable::SizeOfInlineEntries,
     169             :                       "Only tables with the same size for inline entries are usable in the pool.");
     170             :         static_assert(mozilla::IsPod<typename Table::Table::Entry>::value,
     171             :                       "Only tables with POD values are usable in the pool.");
     172       84355 :     }
     173             : };
     174             : 
     175             : using FunctionBoxVector = Vector<FunctionBox*, 24, SystemAllocPolicy>;
     176             : 
     177             : template <typename RepresentativeVector>
     178          40 : class VectorPool : public CollectionPool<RepresentativeVector, VectorPool<RepresentativeVector>>
     179             : {
     180             :   public:
     181             :     template <typename Vector>
     182       30028 :     static void assertInvariants() {
     183             :         static_assert(Vector::sMaxInlineStorage == RepresentativeVector::sMaxInlineStorage,
     184             :                       "Only vectors with the same size for inline entries are usable in the pool.");
     185             :         static_assert(mozilla::IsPod<typename Vector::ElementType>::value,
     186             :                       "Only vectors of POD values are usable in the pool.");
     187             :         static_assert(sizeof(typename Vector::ElementType) ==
     188             :                       sizeof(typename RepresentativeVector::ElementType),
     189             :                       "Only vectors with same-sized elements are usable in the pool.");
     190       30028 :     }
     191             : };
     192             : 
     193           0 : class NameCollectionPool
     194             : {
     195             :     InlineTablePool<AtomIndexMap> mapPool_;
     196             :     VectorPool<AtomVector> vectorPool_;
     197             :     uint32_t activeCompilations_;
     198             : 
     199             :   public:
     200          40 :     NameCollectionPool()
     201          40 :       : activeCompilations_(0)
     202          40 :     { }
     203             : 
     204      167350 :     bool hasActiveCompilation() const {
     205      167350 :         return activeCompilations_ != 0;
     206             :     }
     207             : 
     208        1902 :     void addActiveCompilation() {
     209        1902 :         activeCompilations_++;
     210        1902 :     }
     211             : 
     212        1903 :     void removeActiveCompilation() {
     213        1903 :         MOZ_ASSERT(hasActiveCompilation());
     214        1903 :         activeCompilations_--;
     215        1903 :     }
     216             : 
     217             :     template <typename Map>
     218       42175 :     Map* acquireMap(JSContext* cx) {
     219       42175 :         MOZ_ASSERT(hasActiveCompilation());
     220       42175 :         return mapPool_.acquire<Map>(cx);
     221             :     }
     222             : 
     223             :     template <typename Map>
     224       74039 :     void releaseMap(Map** map) {
     225       74039 :         MOZ_ASSERT(hasActiveCompilation());
     226       74039 :         MOZ_ASSERT(map);
     227       74039 :         if (*map)
     228       42180 :             mapPool_.release(map);
     229       74039 :     }
     230             : 
     231             :     template <typename Vector>
     232       15014 :     Vector* acquireVector(JSContext* cx) {
     233       15014 :         MOZ_ASSERT(hasActiveCompilation());
     234       15014 :         return vectorPool_.acquire<Vector>(cx);
     235             :     }
     236             : 
     237             :     template <typename Vector>
     238       34116 :     void releaseVector(Vector** vec) {
     239       34116 :         MOZ_ASSERT(hasActiveCompilation());
     240       34116 :         MOZ_ASSERT(vec);
     241       34116 :         if (*vec)
     242       15014 :             vectorPool_.release(vec);
     243       34116 :     }
     244             : 
     245           1 :     void purge() {
     246           1 :         if (!hasActiveCompilation()) {
     247           1 :             mapPool_.purgeAll();
     248           1 :             vectorPool_.purgeAll();
     249             :         }
     250           1 :     }
     251             : };
     252             : 
     253             : #define POOLED_COLLECTION_PTR_METHODS(N, T)                       \
     254             :     NameCollectionPool& pool_;                                    \
     255             :     T* collection_;                                               \
     256             :                                                                   \
     257             :     T& collection() {                                             \
     258             :         MOZ_ASSERT(collection_);                                  \
     259             :         return *collection_;                                      \
     260             :     }                                                             \
     261             :                                                                   \
     262             :     const T& collection() const {                                 \
     263             :         MOZ_ASSERT(collection_);                                  \
     264             :         return *collection_;                                      \
     265             :     }                                                             \
     266             :                                                                   \
     267             :   public:                                                         \
     268             :     explicit N(NameCollectionPool& pool)                          \
     269             :       : pool_(pool),                                              \
     270             :         collection_(nullptr)                                      \
     271             :     { }                                                           \
     272             :                                                                   \
     273             :     ~N() {                                                        \
     274             :         pool_.release##T(&collection_);                           \
     275             :     }                                                             \
     276             :                                                                   \
     277             :     bool acquire(JSContext* cx) {                                 \
     278             :         MOZ_ASSERT(!collection_);                                 \
     279             :         collection_ = pool_.acquire##T<T>(cx);                    \
     280             :         return !!collection_;                                     \
     281             :     }                                                             \
     282             :                                                                   \
     283             :     explicit operator bool() const {                              \
     284             :         return !!collection_;                                     \
     285             :     }                                                             \
     286             :                                                                   \
     287             :     T* operator->() {                                             \
     288             :         return &collection();                                     \
     289             :     }                                                             \
     290             :                                                                   \
     291             :     const T* operator->() const {                                 \
     292             :         return &collection();                                     \
     293             :     }                                                             \
     294             :                                                                   \
     295             :     T& operator*() {                                              \
     296             :         return collection();                                      \
     297             :     }                                                             \
     298             :                                                                   \
     299             :     const T& operator*() const {                                  \
     300             :         return collection();                                      \
     301             :     }
     302             : 
     303             : template <typename Map>
     304             : class PooledMapPtr
     305             : {
     306     1320793 :     POOLED_COLLECTION_PTR_METHODS(PooledMapPtr, Map)
     307             : };
     308             : 
     309             : template <typename Vector>
     310             : class PooledVectorPtr
     311             : {
     312      169164 :     POOLED_COLLECTION_PTR_METHODS(PooledVectorPtr, Vector)
     313             : 
     314             :     typename Vector::ElementType& operator[](size_t index) {
     315             :         return collection()[index];
     316             :     }
     317             : 
     318             :     const typename Vector::ElementType& operator[](size_t index) const {
     319             :         return collection()[index];
     320             :     }
     321             : };
     322             : 
     323             : #undef POOLED_COLLECTION_PTR_METHODS
     324             : 
     325             : } // namespace frontend
     326             : } // namespace js
     327             : 
     328             : namespace mozilla {
     329             : 
     330             : template <>
     331             : struct IsPod<js::MaybeCheckTDZ> : TrueType {};
     332             : 
     333             : template <typename T>
     334             : struct IsPod<js::frontend::RecyclableAtomMapValueWrapper<T>> : IsPod<T> {};
     335             : 
     336             : } // namespace mozilla
     337             : 
     338             : #endif // frontend_NameCollections_h

Generated by: LCOV version 1.13