1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jit_JitZone_h
8 #define jit_JitZone_h
9 
10 #include "mozilla/Assertions.h"
11 #include "mozilla/HashFunctions.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/MemoryReporting.h"
14 
15 #include <stddef.h>
16 #include <stdint.h>
17 #include <utility>
18 
19 #include "gc/Barrier.h"
20 #include "jit/ExecutableAllocator.h"
21 #include "jit/ICStubSpace.h"
22 #include "jit/Invalidation.h"
23 #include "js/AllocPolicy.h"
24 #include "js/GCHashTable.h"
25 #include "js/HashTable.h"
26 #include "js/TracingAPI.h"
27 #include "js/TypeDecls.h"
28 #include "js/UniquePtr.h"
29 #include "js/Utility.h"
30 #include "threading/ProtectedData.h"
31 
32 namespace JS {
33 struct CodeSizes;
34 }
35 
36 namespace js {
37 namespace jit {
38 
39 enum class CacheKind : uint8_t;
40 class CacheIRStubInfo;
41 class JitCode;
42 
43 enum class ICStubEngine : uint8_t {
44   // Baseline IC, see BaselineIC.h.
45   Baseline = 0,
46 
47   // Ion IC, see IonIC.h.
48   IonIC
49 };
50 
51 struct CacheIRStubKey : public DefaultHasher<CacheIRStubKey> {
52   struct Lookup {
53     CacheKind kind;
54     ICStubEngine engine;
55     const uint8_t* code;
56     uint32_t length;
57 
LookupCacheIRStubKey::Lookup58     Lookup(CacheKind kind, ICStubEngine engine, const uint8_t* code,
59            uint32_t length)
60         : kind(kind), engine(engine), code(code), length(length) {}
61   };
62 
63   static HashNumber hash(const Lookup& l);
64   static bool match(const CacheIRStubKey& entry, const Lookup& l);
65 
66   UniquePtr<CacheIRStubInfo, JS::FreePolicy> stubInfo;
67 
CacheIRStubKeyCacheIRStubKey68   explicit CacheIRStubKey(CacheIRStubInfo* info) : stubInfo(info) {}
CacheIRStubKeyCacheIRStubKey69   CacheIRStubKey(CacheIRStubKey&& other)
70       : stubInfo(std::move(other.stubInfo)) {}
71 
72   void operator=(CacheIRStubKey&& other) {
73     stubInfo = std::move(other.stubInfo);
74   }
75 };
76 
77 struct BaselineCacheIRStubCodeMapGCPolicy {
traceWeakBaselineCacheIRStubCodeMapGCPolicy78   static bool traceWeak(JSTracer* trc, CacheIRStubKey*,
79                         WeakHeapPtrJitCode* value) {
80     return TraceWeakEdge(trc, value, "traceWeak");
81   }
82 };
83 
84 class JitZone {
85   // Allocated space for optimized baseline stubs.
86   OptimizedICStubSpace optimizedStubSpace_;
87 
88   // Set of CacheIRStubInfo instances used by Ion stubs in this Zone.
89   using IonCacheIRStubInfoSet =
90       HashSet<CacheIRStubKey, CacheIRStubKey, SystemAllocPolicy>;
91   IonCacheIRStubInfoSet ionCacheIRStubInfoSet_;
92 
93   // Map CacheIRStubKey to shared JitCode objects.
94   using BaselineCacheIRStubCodeMap =
95       GCHashMap<CacheIRStubKey, WeakHeapPtrJitCode, CacheIRStubKey,
96                 SystemAllocPolicy, BaselineCacheIRStubCodeMapGCPolicy>;
97   BaselineCacheIRStubCodeMap baselineCacheIRStubCodes_;
98 
99   // Executable allocator for all code except wasm code.
100   MainThreadData<ExecutableAllocator> execAlloc_;
101 
102   // HashMap that maps scripts to compilations inlining those scripts.
103   using InlinedScriptMap =
104       GCHashMap<WeakHeapPtr<BaseScript*>, RecompileInfoVector,
105                 MovableCellHasher<WeakHeapPtr<BaseScript*>>, SystemAllocPolicy>;
106   InlinedScriptMap inlinedCompilations_;
107 
108   mozilla::Maybe<IonCompilationId> currentCompilationId_;
109   bool keepJitScripts_ = false;
110 
111  public:
~JitZone()112   ~JitZone() { MOZ_ASSERT(!keepJitScripts_); }
113 
114   void traceWeak(JSTracer* trc);
115 
116   void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
117                               JS::CodeSizes* code, size_t* jitZone,
118                               size_t* baselineStubsOptimized) const;
119 
optimizedStubSpace()120   OptimizedICStubSpace* optimizedStubSpace() { return &optimizedStubSpace_; }
121 
getBaselineCacheIRStubCode(const CacheIRStubKey::Lookup & key,CacheIRStubInfo ** stubInfo)122   JitCode* getBaselineCacheIRStubCode(const CacheIRStubKey::Lookup& key,
123                                       CacheIRStubInfo** stubInfo) {
124     auto p = baselineCacheIRStubCodes_.lookup(key);
125     if (p) {
126       *stubInfo = p->key().stubInfo.get();
127       return p->value();
128     }
129     *stubInfo = nullptr;
130     return nullptr;
131   }
putBaselineCacheIRStubCode(const CacheIRStubKey::Lookup & lookup,CacheIRStubKey & key,JitCode * stubCode)132   [[nodiscard]] bool putBaselineCacheIRStubCode(
133       const CacheIRStubKey::Lookup& lookup, CacheIRStubKey& key,
134       JitCode* stubCode) {
135     auto p = baselineCacheIRStubCodes_.lookupForAdd(lookup);
136     MOZ_ASSERT(!p);
137     return baselineCacheIRStubCodes_.add(p, std::move(key), stubCode);
138   }
139 
getIonCacheIRStubInfo(const CacheIRStubKey::Lookup & key)140   CacheIRStubInfo* getIonCacheIRStubInfo(const CacheIRStubKey::Lookup& key) {
141     IonCacheIRStubInfoSet::Ptr p = ionCacheIRStubInfoSet_.lookup(key);
142     return p ? p->stubInfo.get() : nullptr;
143   }
putIonCacheIRStubInfo(const CacheIRStubKey::Lookup & lookup,CacheIRStubKey & key)144   [[nodiscard]] bool putIonCacheIRStubInfo(const CacheIRStubKey::Lookup& lookup,
145                                            CacheIRStubKey& key) {
146     IonCacheIRStubInfoSet::AddPtr p =
147         ionCacheIRStubInfoSet_.lookupForAdd(lookup);
148     MOZ_ASSERT(!p);
149     return ionCacheIRStubInfoSet_.add(p, std::move(key));
150   }
purgeIonCacheIRStubInfo()151   void purgeIonCacheIRStubInfo() { ionCacheIRStubInfoSet_.clearAndCompact(); }
152 
execAlloc()153   ExecutableAllocator& execAlloc() { return execAlloc_.ref(); }
execAlloc()154   const ExecutableAllocator& execAlloc() const { return execAlloc_.ref(); }
155 
156   [[nodiscard]] bool addInlinedCompilation(const RecompileInfo& info,
157                                            JSScript* inlined);
158 
maybeInlinedCompilations(JSScript * inlined)159   RecompileInfoVector* maybeInlinedCompilations(JSScript* inlined) {
160     auto p = inlinedCompilations_.lookup(inlined);
161     return p ? &p->value() : nullptr;
162   }
163 
removeInlinedCompilations(JSScript * inlined)164   void removeInlinedCompilations(JSScript* inlined) {
165     inlinedCompilations_.remove(inlined);
166   }
167 
keepJitScripts()168   bool keepJitScripts() const { return keepJitScripts_; }
setKeepJitScripts(bool keep)169   void setKeepJitScripts(bool keep) { keepJitScripts_ = keep; }
170 
currentCompilationId()171   mozilla::Maybe<IonCompilationId> currentCompilationId() const {
172     return currentCompilationId_;
173   }
currentCompilationIdRef()174   mozilla::Maybe<IonCompilationId>& currentCompilationIdRef() {
175     return currentCompilationId_;
176   }
177 };
178 
179 }  // namespace jit
180 }  // namespace js
181 
182 #endif /* jit_JitZone_h */
183