LCOV - code coverage report
Current view: top level - js/src/vm - Caches.h (source / functions) Hit Total Coverage
Test: output.info Lines: 53 59 89.8 %
Date: 2017-07-14 16:53:18 Functions: 22 27 81.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 vm_Caches_h
       8             : #define vm_Caches_h
       9             : 
      10             : #include "jsatom.h"
      11             : #include "jsbytecode.h"
      12             : #include "jsmath.h"
      13             : #include "jsobj.h"
      14             : #include "jsscript.h"
      15             : 
      16             : #include "ds/FixedSizeHash.h"
      17             : #include "frontend/SourceNotes.h"
      18             : #include "gc/Tracer.h"
      19             : #include "js/RootingAPI.h"
      20             : #include "js/UniquePtr.h"
      21             : #include "vm/NativeObject.h"
      22             : 
      23             : namespace js {
      24             : 
      25             : /*
      26             :  * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
      27             :  * given pc in a script. We use the script->code pointer to tag the cache,
      28             :  * instead of the script address itself, so that source notes are always found
      29             :  * by offset from the bytecode with which they were generated.
      30             :  */
      31         319 : struct GSNCache {
      32             :     typedef HashMap<jsbytecode*,
      33             :                     jssrcnote*,
      34             :                     PointerHasher<jsbytecode*, 0>,
      35             :                     SystemAllocPolicy> Map;
      36             : 
      37             :     jsbytecode*     code;
      38             :     Map             map;
      39             : 
      40         333 :     GSNCache() : code(nullptr) { }
      41             : 
      42             :     void purge();
      43             : };
      44             : 
      45             : /*
      46             :  * EnvironmentCoordinateName cache to avoid O(n^2) growth in finding the name
      47             :  * associated with a given aliasedvar operation.
      48             :  */
      49         169 : struct EnvironmentCoordinateNameCache {
      50             :     typedef HashMap<uint32_t,
      51             :                     jsid,
      52             :                     DefaultHasher<uint32_t>,
      53             :                     SystemAllocPolicy> Map;
      54             : 
      55             :     Shape* shape;
      56             :     Map map;
      57             : 
      58         183 :     EnvironmentCoordinateNameCache() : shape(nullptr) {}
      59             :     void purge();
      60             : };
      61             : 
      62             : struct EvalCacheEntry
      63             : {
      64             :     JSLinearString* str;
      65             :     JSScript* script;
      66             :     JSScript* callerScript;
      67             :     jsbytecode* pc;
      68             : };
      69             : 
      70           2 : struct EvalCacheLookup
      71             : {
      72           2 :     explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
      73             :     RootedLinearString str;
      74             :     RootedScript callerScript;
      75             :     JSVersion version;
      76             :     jsbytecode* pc;
      77             : };
      78             : 
      79             : struct EvalCacheHashPolicy
      80             : {
      81             :     typedef EvalCacheLookup Lookup;
      82             : 
      83             :     static HashNumber hash(const Lookup& l);
      84             :     static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
      85             : };
      86             : 
      87             : typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
      88             : 
      89             : struct LazyScriptHashPolicy
      90             : {
      91             :     struct Lookup {
      92             :         JSContext* cx;
      93             :         LazyScript* lazy;
      94             : 
      95        2423 :         Lookup(JSContext* cx, LazyScript* lazy)
      96        2423 :           : cx(cx), lazy(lazy)
      97        2423 :         {}
      98             :     };
      99             : 
     100             :     static const size_t NumHashes = 3;
     101             : 
     102             :     static void hash(const Lookup& lookup, HashNumber hashes[NumHashes]);
     103             :     static bool match(JSScript* script, const Lookup& lookup);
     104             : 
     105             :     // Alternate methods for use when removing scripts from the hash without an
     106             :     // explicit LazyScript lookup.
     107             :     static void hash(JSScript* script, HashNumber hashes[NumHashes]);
     108           0 :     static bool match(JSScript* script, JSScript* lookup) { return script == lookup; }
     109             : 
     110           0 :     static void clear(JSScript** pscript) { *pscript = nullptr; }
     111        4851 :     static bool isCleared(JSScript* script) { return !script; }
     112             : };
     113             : 
     114             : typedef FixedSizeHashSet<JSScript*, LazyScriptHashPolicy, 769> LazyScriptCache;
     115             : 
     116             : class PropertyIteratorObject;
     117             : 
     118             : class NativeIterCache
     119             : {
     120             :     static const size_t SIZE = size_t(1) << 8;
     121             : 
     122             :     /* Cached native iterators. */
     123             :     PropertyIteratorObject* data[SIZE];
     124             : 
     125         143 :     static size_t getIndex(uint32_t key) {
     126         143 :         return size_t(key) % SIZE;
     127             :     }
     128             : 
     129             :   public:
     130           4 :     NativeIterCache() {
     131           4 :         mozilla::PodArrayZero(data);
     132           4 :     }
     133             : 
     134           1 :     void purge() {
     135           1 :         mozilla::PodArrayZero(data);
     136           1 :     }
     137             : 
     138          87 :     PropertyIteratorObject* get(uint32_t key) const {
     139          87 :         return data[getIndex(key)];
     140             :     }
     141             : 
     142          56 :     void set(uint32_t key, PropertyIteratorObject* iterobj) {
     143          56 :         data[getIndex(key)] = iterobj;
     144          56 :     }
     145             : };
     146             : 
     147             : /*
     148             :  * Cache for speeding up repetitive creation of objects in the VM.
     149             :  * When an object is created which matches the criteria in the 'key' section
     150             :  * below, an entry is filled with the resulting object.
     151             :  */
     152             : class NewObjectCache
     153             : {
     154             :     /* Statically asserted to be equal to sizeof(JSObject_Slots16) */
     155             :     static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
     156             : 
     157             :     static void staticAsserts() {
     158             :         JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
     159             :         JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
     160             :     }
     161             : 
     162             :     struct Entry
     163             :     {
     164             :         /* Class of the constructed object. */
     165             :         const Class* clasp;
     166             : 
     167             :         /*
     168             :          * Key with one of three possible values:
     169             :          *
     170             :          * - Global for the object. The object must have a standard class for
     171             :          *   which the global's prototype can be determined, and the object's
     172             :          *   parent will be the global.
     173             :          *
     174             :          * - Prototype for the object (cannot be global). The object's parent
     175             :          *   will be the prototype's parent.
     176             :          *
     177             :          * - Type for the object. The object's parent will be the type's
     178             :          *   prototype's parent.
     179             :          */
     180             :         gc::Cell* key;
     181             : 
     182             :         /* Allocation kind for the constructed object. */
     183             :         gc::AllocKind kind;
     184             : 
     185             :         /* Number of bytes to copy from the template object. */
     186             :         uint32_t nbytes;
     187             : 
     188             :         /*
     189             :          * Template object to copy from, with the initial values of fields,
     190             :          * fixed slots (undefined) and private data (nullptr).
     191             :          */
     192             :         char templateObject[MAX_OBJ_SIZE];
     193             :     };
     194             : 
     195             :     Entry entries[41];  // TODO: reconsider size
     196             : 
     197             :   public:
     198             : 
     199             :     typedef int EntryIndex;
     200             : 
     201           4 :     NewObjectCache() { mozilla::PodZero(this); }
     202           1 :     void purge() { mozilla::PodZero(this); }
     203             : 
     204             :     /* Remove any cached items keyed on moved objects. */
     205             :     void clearNurseryObjects(JSRuntime* rt);
     206             : 
     207             :     /*
     208             :      * Get the entry index for the given lookup, return whether there was a hit
     209             :      * on an existing entry.
     210             :      */
     211             :     inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
     212             :     inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
     213             :                              EntryIndex* pentry);
     214             : 
     215         322 :     bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
     216         322 :         return lookup(group->clasp(), group, kind, pentry);
     217             :     }
     218             : 
     219             :     /*
     220             :      * Return a new object from a cache hit produced by a lookup method, or
     221             :      * nullptr if returning the object could possibly trigger GC (does not
     222             :      * indicate failure).
     223             :      */
     224             :     inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
     225             : 
     226             :     /* Fill an entry after a cache miss. */
     227             :     void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
     228             :                    gc::AllocKind kind, NativeObject* obj);
     229             : 
     230             :     inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
     231             :                            gc::AllocKind kind, NativeObject* obj);
     232             : 
     233          57 :     void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
     234             :                    NativeObject* obj)
     235             :     {
     236          57 :         MOZ_ASSERT(obj->group() == group);
     237          57 :         return fill(entry, group->clasp(), group, kind, obj);
     238             :     }
     239             : 
     240             :     /* Invalidate any entries which might produce an object with shape/proto. */
     241             :     void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
     242             : 
     243             :   private:
     244       46057 :     EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
     245       46057 :         uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
     246       46057 :         return hash % mozilla::ArrayLength(entries);
     247             :     }
     248             : 
     249       38965 :     bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
     250       38965 :         *pentry = makeIndex(clasp, key, kind);
     251       38965 :         Entry* entry = &entries[*pentry];
     252             : 
     253             :         /* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
     254       38965 :         return entry->clasp == clasp && entry->key == key;
     255             :     }
     256             : 
     257        7089 :     void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
     258             :               NativeObject* obj) {
     259        7089 :         MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
     260        7089 :         MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
     261        7089 :         Entry* entry = &entries[entry_];
     262             : 
     263        7089 :         entry->clasp = clasp;
     264        7089 :         entry->key = key;
     265        7089 :         entry->kind = kind;
     266             : 
     267        7089 :         entry->nbytes = gc::Arena::thingSize(kind);
     268        7089 :         js_memcpy(&entry->templateObject, obj, entry->nbytes);
     269        7089 :     }
     270             : 
     271       24321 :     static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
     272       24321 :         js_memcpy(dst, src, gc::Arena::thingSize(kind));
     273       24321 :         Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
     274       24321 :         ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
     275       24321 :     }
     276             : };
     277             : 
     278           4 : class RuntimeCaches
     279             : {
     280             :     UniquePtr<js::MathCache> mathCache_;
     281             : 
     282             :     js::MathCache* createMathCache(JSContext* cx);
     283             : 
     284             :   public:
     285             :     js::GSNCache gsnCache;
     286             :     js::EnvironmentCoordinateNameCache envCoordinateNameCache;
     287             :     js::NewObjectCache newObjectCache;
     288             :     js::NativeIterCache nativeIterCache;
     289             :     js::UncompressedSourceCache uncompressedSourceCache;
     290             :     js::EvalCache evalCache;
     291             :     LazyScriptCache lazyScriptCache;
     292             : 
     293             :     bool init();
     294             : 
     295           0 :     js::MathCache* getMathCache(JSContext* cx) {
     296           0 :         return mathCache_ ? mathCache_.get() : createMathCache(cx);
     297             :     }
     298           0 :     js::MathCache* maybeGetMathCache() {
     299           0 :         return mathCache_.get();
     300             :     }
     301             : };
     302             : 
     303             : } // namespace js
     304             : 
     305             : #endif /* vm_Caches_h */

Generated by: LCOV version 1.13