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 vm_ShapeZone_h
8 #define vm_ShapeZone_h
9 
10 #include "mozilla/MemoryReporting.h"
11 
12 #include "gc/Barrier.h"
13 #include "js/GCHashTable.h"
14 #include "vm/PropertyKey.h"
15 #include "vm/PropMap.h"
16 #include "vm/Shape.h"
17 #include "vm/TaggedProto.h"
18 
19 namespace js {
20 
21 // Hash policy for the per-zone baseShapes set.
22 struct BaseShapeHasher {
23   struct Lookup {
24     const JSClass* clasp;
25     JS::Realm* realm;
26     TaggedProto proto;
27 
LookupBaseShapeHasher::Lookup28     Lookup(const JSClass* clasp, JS::Realm* realm, TaggedProto proto)
29         : clasp(clasp), realm(realm), proto(proto) {}
30   };
31 
hashBaseShapeHasher32   static HashNumber hash(const Lookup& lookup) {
33     HashNumber hash = MovableCellHasher<TaggedProto>::hash(lookup.proto);
34     return mozilla::AddToHash(hash, lookup.clasp, lookup.realm);
35   }
matchBaseShapeHasher36   static bool match(const WeakHeapPtr<BaseShape*>& key, const Lookup& lookup) {
37     return key.unbarrieredGet()->clasp() == lookup.clasp &&
38            key.unbarrieredGet()->realm() == lookup.realm &&
39            key.unbarrieredGet()->proto() == lookup.proto;
40   }
41 };
42 using BaseShapeSet = JS::WeakCache<
43     JS::GCHashSet<WeakHeapPtr<BaseShape*>, BaseShapeHasher, SystemAllocPolicy>>;
44 
45 // Hash policy for the per-zone initialPropMaps set, mapping property key + info
46 // to a shared property map.
47 struct InitialPropMapHasher {
48   struct Lookup {
49     PropertyKey key;
50     PropertyInfo prop;
51 
LookupInitialPropMapHasher::Lookup52     Lookup(PropertyKey key, PropertyInfo prop) : key(key), prop(prop) {}
53   };
hashInitialPropMapHasher54   static HashNumber hash(const Lookup& lookup) {
55     HashNumber hash = HashPropertyKey(lookup.key);
56     return mozilla::AddToHash(hash, lookup.prop.toRaw());
57   }
matchInitialPropMapHasher58   static bool match(const WeakHeapPtr<SharedPropMap*>& key,
59                     const Lookup& lookup) {
60     const SharedPropMap* map = key.unbarrieredGet();
61     return map->matchProperty(0, lookup.key, lookup.prop);
62   }
63 };
64 using InitialPropMapSet =
65     JS::WeakCache<JS::GCHashSet<WeakHeapPtr<SharedPropMap*>,
66                                 InitialPropMapHasher, SystemAllocPolicy>>;
67 
68 // Hash policy for the per-zone initialShapes set storing initial shapes for
69 // objects in the zone.
70 //
71 // These are empty shapes, except for certain classes (e.g. String, RegExp)
72 // which may add certain baked-in properties. See insertInitialShape.
73 struct InitialShapeHasher {
74   struct Lookup {
75     const JSClass* clasp;
76     JS::Realm* realm;
77     TaggedProto proto;
78     uint32_t nfixed;
79     ObjectFlags objectFlags;
80 
LookupInitialShapeHasher::Lookup81     Lookup(const JSClass* clasp, JS::Realm* realm, const TaggedProto& proto,
82            uint32_t nfixed, ObjectFlags objectFlags)
83         : clasp(clasp),
84           realm(realm),
85           proto(proto),
86           nfixed(nfixed),
87           objectFlags(objectFlags) {}
88   };
89 
hashInitialShapeHasher90   static HashNumber hash(const Lookup& lookup) {
91     HashNumber hash = MovableCellHasher<TaggedProto>::hash(lookup.proto);
92     return mozilla::AddToHash(hash, lookup.clasp, lookup.realm, lookup.nfixed,
93                               lookup.objectFlags.toRaw());
94   }
matchInitialShapeHasher95   static bool match(const WeakHeapPtr<Shape*>& key, const Lookup& lookup) {
96     const Shape* shape = key.unbarrieredGet();
97     return lookup.clasp == shape->getObjectClass() &&
98            lookup.realm == shape->realm() && lookup.proto == shape->proto() &&
99            lookup.nfixed == shape->numFixedSlots() &&
100            lookup.objectFlags == shape->objectFlags();
101   }
102 };
103 using InitialShapeSet = JS::WeakCache<
104     JS::GCHashSet<WeakHeapPtr<Shape*>, InitialShapeHasher, SystemAllocPolicy>>;
105 
106 // Hash policy for the per-zone propMapShapes set storing shared shapes with
107 // shared property maps.
108 struct PropMapShapeHasher {
109   struct Lookup {
110     BaseShape* base;
111     SharedPropMap* map;
112     uint32_t mapLength;
113     uint32_t nfixed;
114     ObjectFlags objectFlags;
115 
LookupPropMapShapeHasher::Lookup116     Lookup(BaseShape* base, uint32_t nfixed, SharedPropMap* map,
117            uint32_t mapLength, ObjectFlags objectFlags)
118         : base(base),
119           map(map),
120           mapLength(mapLength),
121           nfixed(nfixed),
122           objectFlags(objectFlags) {}
123   };
124 
hashPropMapShapeHasher125   static HashNumber hash(const Lookup& lookup) {
126     return mozilla::HashGeneric(lookup.base, lookup.map, lookup.mapLength,
127                                 lookup.nfixed, lookup.objectFlags.toRaw());
128   }
matchPropMapShapeHasher129   static bool match(const WeakHeapPtr<Shape*>& key, const Lookup& lookup) {
130     const Shape* shape = key.unbarrieredGet();
131     return lookup.base == shape->base() &&
132            lookup.nfixed == shape->numFixedSlots() &&
133            lookup.map == shape->propMap() &&
134            lookup.mapLength == shape->propMapLength() &&
135            lookup.objectFlags == shape->objectFlags();
136   }
rekeyPropMapShapeHasher137   static void rekey(WeakHeapPtr<Shape*>& k, const WeakHeapPtr<Shape*>& newKey) {
138     k = newKey;
139   }
140 };
141 using PropMapShapeSet = JS::WeakCache<
142     JS::GCHashSet<WeakHeapPtr<Shape*>, PropMapShapeHasher, SystemAllocPolicy>>;
143 
144 struct ShapeZone {
145   // Set of all base shapes in the Zone.
146   BaseShapeSet baseShapes;
147 
148   // Set used to look up a shared property map based on the first property's
149   // PropertyKey and PropertyInfo.
150   InitialPropMapSet initialPropMaps;
151 
152   // Set of initial shapes in the Zone.
153   InitialShapeSet initialShapes;
154 
155   // Set of SharedPropMapShapes in the Zone.
156   PropMapShapeSet propMapShapes;
157 
158   using ShapeWithCacheVector = js::Vector<js::Shape*, 0, js::SystemAllocPolicy>;
159   ShapeWithCacheVector shapesWithCache;
160 
161   explicit ShapeZone(Zone* zone);
162 
163   void purgeShapeCaches(JSFreeOp* fop);
164 
165   void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
166                               size_t* initialPropMapTable, size_t* shapeTables);
167 
168   void fixupPropMapShapeTableAfterMovingGC();
169 
170 #ifdef JSGC_HASH_TABLE_CHECKS
171   void checkTablesAfterMovingGC();
172 #endif
173 };
174 
175 }  // namespace js
176 
177 #endif /* vm_ShapeZone_h */
178