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_ObjectGroup_h
8 : #define vm_ObjectGroup_h
9 :
10 : #include "jsbytecode.h"
11 : #include "jsfriendapi.h"
12 :
13 : #include "ds/IdValuePair.h"
14 : #include "gc/Barrier.h"
15 : #include "js/CharacterEncoding.h"
16 : #include "js/GCHashTable.h"
17 : #include "vm/TaggedProto.h"
18 : #include "vm/TypeInference.h"
19 :
20 : namespace js {
21 :
22 : class TypeDescr;
23 : class UnboxedLayout;
24 :
25 : class PreliminaryObjectArrayWithTemplate;
26 : class TypeNewScript;
27 : class HeapTypeSet;
28 : class AutoClearTypeInferenceStateOnOOM;
29 : class CompilerConstraintList;
30 :
31 : namespace gc {
32 : void MergeCompartments(JSCompartment* source, JSCompartment* target);
33 : } // namespace gc
34 :
35 : /*
36 : * The NewObjectKind allows an allocation site to specify the type properties
37 : * and lifetime requirements that must be fixed at allocation time.
38 : */
39 : enum NewObjectKind {
40 : /* This is the default. Most objects are generic. */
41 : GenericObject,
42 :
43 : /*
44 : * Singleton objects are treated specially by the type system. This flag
45 : * ensures that the new object is automatically set up correctly as a
46 : * singleton and is allocated in the tenured heap.
47 : */
48 : SingletonObject,
49 :
50 : /*
51 : * CrossCompartmentWrappers use the common Proxy class, but are allowed
52 : * to have nursery lifetime.
53 : */
54 : NurseryAllocatedProxy,
55 :
56 : /*
57 : * Objects which will not benefit from being allocated in the nursery
58 : * (e.g. because they are known to have a long lifetime) may be allocated
59 : * with this kind to place them immediately into the tenured generation.
60 : */
61 : TenuredObject
62 : };
63 :
64 : /*
65 : * Lazy object groups overview.
66 : *
67 : * Object groups which represent at most one JS object are constructed lazily.
68 : * These include groups for native functions, standard classes, scripted
69 : * functions defined at the top level of global/eval scripts, objects which
70 : * dynamically become the prototype of some other object, and in some other
71 : * cases. Typical web workloads often create many windows (and many copies of
72 : * standard natives) and many scripts, with comparatively few non-singleton
73 : * groups.
74 : *
75 : * We can recover the type information for the object from examining it,
76 : * so don't normally track the possible types of its properties as it is
77 : * updated. Property type sets for the object are only constructed when an
78 : * analyzed script attaches constraints to it: the script is querying that
79 : * property off the object or another which delegates to it, and the analysis
80 : * information is sensitive to changes in the property's type. Future changes
81 : * to the property (whether those uncovered by analysis or those occurring
82 : * in the VM) will treat these properties like those of any other object group.
83 : */
84 :
85 : /* Type information about an object accessed by a script. */
86 : class ObjectGroup : public gc::TenuredCell
87 : {
88 : friend void gc::MergeCompartments(JSCompartment* source, JSCompartment* target);
89 :
90 : /* Class shared by objects in this group. */
91 : const Class* clasp_;
92 :
93 : /* Prototype shared by objects in this group. */
94 : GCPtr<TaggedProto> proto_;
95 :
96 : /* Compartment shared by objects in this group. */
97 : JSCompartment* compartment_;
98 :
99 : public:
100 :
101 13223938 : const Class* clasp() const {
102 13223938 : return clasp_;
103 : }
104 :
105 2927 : void setClasp(const Class* clasp) {
106 2927 : MOZ_ASSERT(JS::StringIsASCII(clasp->name));
107 2927 : clasp_ = clasp;
108 2927 : }
109 :
110 : bool hasDynamicPrototype() const {
111 : return proto_.isDynamic();
112 : }
113 :
114 : const GCPtr<TaggedProto>& proto() const {
115 : return proto_;
116 : }
117 :
118 1136473 : GCPtr<TaggedProto>& proto() {
119 1136473 : return proto_;
120 : }
121 :
122 : void setProto(TaggedProto proto);
123 : void setProtoUnchecked(TaggedProto proto);
124 :
125 704723 : bool singleton() const {
126 704723 : return flagsDontCheckGeneration() & OBJECT_FLAG_SINGLETON;
127 : }
128 :
129 731645 : bool lazy() const {
130 731645 : bool res = flagsDontCheckGeneration() & OBJECT_FLAG_LAZY_SINGLETON;
131 731635 : MOZ_ASSERT_IF(res, singleton());
132 731635 : return res;
133 : }
134 :
135 2004655 : JSCompartment* compartment() const { return compartment_; }
136 5744 : JSCompartment* maybeCompartment() const { return compartment(); }
137 :
138 : private:
139 : /* Flags for this group. */
140 : ObjectGroupFlags flags_;
141 :
142 : public:
143 : // Kinds of addendums which can be attached to ObjectGroups.
144 : enum AddendumKind {
145 : Addendum_None,
146 :
147 : // When used by interpreted function, the addendum stores the
148 : // canonical JSFunction object.
149 : Addendum_InterpretedFunction,
150 :
151 : // When used by the 'new' group when constructing an interpreted
152 : // function, the addendum stores a TypeNewScript.
153 : Addendum_NewScript,
154 :
155 : // For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate.
156 : Addendum_PreliminaryObjects,
157 :
158 : // When objects in this group have an unboxed representation, the
159 : // addendum stores an UnboxedLayout (which might have a TypeNewScript
160 : // as well, if the group is also constructed using 'new').
161 : Addendum_UnboxedLayout,
162 :
163 : // If this group is used by objects that have been converted from an
164 : // unboxed representation and/or have the same allocation kind as such
165 : // objects, the addendum points to that unboxed group.
166 : Addendum_OriginalUnboxedGroup,
167 :
168 : // When used by typed objects, the addendum stores a TypeDescr.
169 : Addendum_TypeDescr
170 : };
171 :
172 : private:
173 : // If non-null, holds additional information about this object, whose
174 : // format is indicated by the object's addendum kind.
175 : void* addendum_;
176 :
177 : void setAddendum(AddendumKind kind, void* addendum, bool writeBarrier = true);
178 :
179 649804 : AddendumKind addendumKind() const {
180 : return (AddendumKind)
181 649804 : ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
182 : }
183 :
184 320372 : TypeNewScript* newScriptDontCheckGeneration() const {
185 320372 : if (addendumKind() == Addendum_NewScript)
186 8733 : return reinterpret_cast<TypeNewScript*>(addendum_);
187 311642 : return nullptr;
188 : }
189 :
190 : TypeNewScript* anyNewScript();
191 : void detachNewScript(bool writeBarrier, ObjectGroup* replacement);
192 :
193 2529899 : ObjectGroupFlags flagsDontCheckGeneration() const {
194 2529899 : return flags_;
195 : }
196 :
197 : public:
198 :
199 : inline ObjectGroupFlags flags();
200 : inline void addFlags(ObjectGroupFlags flags);
201 : inline void clearFlags(ObjectGroupFlags flags);
202 : inline TypeNewScript* newScript();
203 :
204 196 : void setNewScript(TypeNewScript* newScript) {
205 196 : MOZ_ASSERT(newScript);
206 196 : setAddendum(Addendum_NewScript, newScript);
207 196 : }
208 1 : void detachNewScript() {
209 1 : setAddendum(Addendum_None, nullptr);
210 1 : }
211 :
212 : inline PreliminaryObjectArrayWithTemplate* maybePreliminaryObjects();
213 :
214 197172 : PreliminaryObjectArrayWithTemplate* maybePreliminaryObjectsDontCheckGeneration() {
215 197172 : if (addendumKind() == Addendum_PreliminaryObjects)
216 17935 : return reinterpret_cast<PreliminaryObjectArrayWithTemplate*>(addendum_);
217 179237 : return nullptr;
218 : }
219 :
220 3278 : void setPreliminaryObjects(PreliminaryObjectArrayWithTemplate* preliminaryObjects) {
221 3278 : setAddendum(Addendum_PreliminaryObjects, preliminaryObjects);
222 3278 : }
223 :
224 58 : void detachPreliminaryObjects() {
225 58 : MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration());
226 58 : setAddendum(Addendum_None, nullptr);
227 58 : }
228 :
229 169048 : bool hasUnanalyzedPreliminaryObjects() {
230 337648 : return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
231 337648 : maybePreliminaryObjectsDontCheckGeneration();
232 : }
233 :
234 : inline UnboxedLayout* maybeUnboxedLayout();
235 : inline UnboxedLayout& unboxedLayout();
236 :
237 57851 : UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
238 57851 : if (addendumKind() == Addendum_UnboxedLayout)
239 14747 : return reinterpret_cast<UnboxedLayout*>(addendum_);
240 43104 : return nullptr;
241 : }
242 :
243 14625 : UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
244 14625 : MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
245 14625 : return *maybeUnboxedLayoutDontCheckGeneration();
246 : }
247 :
248 19 : void setUnboxedLayout(UnboxedLayout* layout) {
249 19 : setAddendum(Addendum_UnboxedLayout, layout);
250 19 : }
251 :
252 31423 : ObjectGroup* maybeOriginalUnboxedGroup() const {
253 31423 : if (addendumKind() == Addendum_OriginalUnboxedGroup)
254 1 : return reinterpret_cast<ObjectGroup*>(addendum_);
255 31422 : return nullptr;
256 : }
257 :
258 4 : void setOriginalUnboxedGroup(ObjectGroup* group) {
259 4 : setAddendum(Addendum_OriginalUnboxedGroup, group);
260 4 : }
261 :
262 507 : TypeDescr* maybeTypeDescr() {
263 : // Note: there is no need to sweep when accessing the type descriptor
264 : // of an object, as it is strongly held and immutable.
265 507 : if (addendumKind() == Addendum_TypeDescr)
266 0 : return reinterpret_cast<TypeDescr*>(addendum_);
267 507 : return nullptr;
268 : }
269 :
270 0 : TypeDescr& typeDescr() {
271 0 : MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
272 0 : return *maybeTypeDescr();
273 : }
274 :
275 0 : void setTypeDescr(TypeDescr* descr) {
276 0 : setAddendum(Addendum_TypeDescr, descr);
277 0 : }
278 :
279 1141 : JSFunction* maybeInterpretedFunction() {
280 : // Note: as with type descriptors, there is no need to sweep when
281 : // accessing the interpreted function associated with an object.
282 1141 : if (addendumKind() == Addendum_InterpretedFunction)
283 340 : return reinterpret_cast<JSFunction*>(addendum_);
284 801 : return nullptr;
285 : }
286 :
287 22790 : void setInterpretedFunction(JSFunction* fun) {
288 22790 : setAddendum(Addendum_InterpretedFunction, fun);
289 22790 : }
290 :
291 : class Property
292 : {
293 : public:
294 : // Identifier for this property, JSID_VOID for the aggregate integer
295 : // index property, or JSID_EMPTY for properties holding constraints
296 : // listening to changes in the group's state.
297 : GCPtrId id;
298 :
299 : // Possible own types for this property.
300 : HeapTypeSet types;
301 :
302 24801 : explicit Property(jsid id)
303 24801 : : id(id)
304 24801 : {}
305 :
306 0 : Property(const Property& o)
307 0 : : id(o.id.get()), types(o.types)
308 0 : {}
309 :
310 38845 : static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
311 258325 : static jsid getKey(Property* p) { return p->id; }
312 : };
313 :
314 : private:
315 : /*
316 : * Properties of this object.
317 : *
318 : * The type sets in the properties of a group describe the possible values
319 : * that can be read out of that property in actual JS objects. In native
320 : * objects, property types account for plain data properties (those with a
321 : * slot and no getter or setter hook) and dense elements. In typed objects
322 : * and unboxed objects, property types account for object and value
323 : * properties and elements in the object, and expando properties in unboxed
324 : * objects.
325 : *
326 : * For accesses on these properties, the correspondence is as follows:
327 : *
328 : * 1. If the group has unknownProperties(), the possible properties and
329 : * value types for associated JSObjects are unknown.
330 : *
331 : * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
332 : * in |obj|, before obj->getProperty(id) the property in |group| for
333 : * |id| must reflect the result of the getProperty.
334 : *
335 : * There are several exceptions to this:
336 : *
337 : * 1. For properties of global JS objects which are undefined at the point
338 : * where the property was (lazily) generated, the property type set will
339 : * remain empty, and the 'undefined' type will only be added after a
340 : * subsequent assignment or deletion. After these properties have been
341 : * assigned a defined value, the only way they can become undefined
342 : * again is after such an assign or deletion.
343 : *
344 : * 2. Array lengths are special cased by the compiler and VM and are not
345 : * reflected in property types.
346 : *
347 : * 3. In typed objects (but not unboxed objects), the initial values of
348 : * properties (null pointers and undefined values) are not reflected in
349 : * the property types. These values are always possible when reading the
350 : * property.
351 : *
352 : * We establish these by using write barriers on calls to setProperty and
353 : * defineProperty which are on native properties, and on any jitcode which
354 : * might update the property with a new type.
355 : */
356 : Property** propertySet;
357 : public:
358 :
359 : inline ObjectGroup(const Class* clasp, TaggedProto proto, JSCompartment* comp,
360 : ObjectGroupFlags initialFlags);
361 :
362 : inline bool hasAnyFlags(ObjectGroupFlags flags);
363 : inline bool hasAllFlags(ObjectGroupFlags flags);
364 :
365 0 : bool hasAllFlagsDontCheckGeneration(ObjectGroupFlags flags) {
366 0 : MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
367 0 : return (this->flagsDontCheckGeneration() & flags) == flags;
368 : }
369 :
370 : inline bool unknownProperties();
371 :
372 0 : bool unknownPropertiesDontCheckGeneration() {
373 0 : MOZ_ASSERT_IF(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
374 : hasAllFlagsDontCheckGeneration(OBJECT_FLAG_DYNAMIC_MASK));
375 0 : return !!(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
376 : }
377 :
378 : inline bool shouldPreTenure();
379 :
380 : gc::InitialHeap initialHeap(CompilerConstraintList* constraints);
381 :
382 : inline bool canPreTenure();
383 : inline bool fromAllocationSite();
384 : inline void setShouldPreTenure(JSContext* cx);
385 :
386 : /*
387 : * Get or create a property of this object. Only call this for properties which
388 : * a script accesses explicitly.
389 : */
390 : inline HeapTypeSet* getProperty(JSContext* cx, JSObject* obj, jsid id);
391 :
392 : /* Get a property only if it already exists. */
393 : MOZ_ALWAYS_INLINE HeapTypeSet* maybeGetProperty(jsid id);
394 :
395 : /*
396 : * Iterate through the group's properties. getPropertyCount overapproximates
397 : * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
398 : * getProperty may return nullptr.
399 : */
400 : inline unsigned getPropertyCount();
401 : inline Property* getProperty(unsigned i);
402 :
403 : /* Helpers */
404 :
405 : void updateNewPropertyTypes(JSContext* cx, JSObject* obj, jsid id, HeapTypeSet* types);
406 : void addDefiniteProperties(JSContext* cx, Shape* shape);
407 : bool matchDefiniteProperties(HandleObject obj);
408 : void markPropertyNonData(JSContext* cx, JSObject* obj, jsid id);
409 : void markPropertyNonWritable(JSContext* cx, JSObject* obj, jsid id);
410 : void markStateChange(JSContext* cx);
411 : void setFlags(JSContext* cx, ObjectGroupFlags flags);
412 : void markUnknown(JSContext* cx);
413 : void maybeClearNewScriptOnOOM();
414 : void clearNewScript(JSContext* cx, ObjectGroup* replacement = nullptr);
415 :
416 : void print();
417 :
418 : inline void clearProperties();
419 : void traceChildren(JSTracer* trc);
420 :
421 : inline bool needsSweep();
422 : inline void maybeSweep(AutoClearTypeInferenceStateOnOOM* oom);
423 :
424 : private:
425 : void sweep(AutoClearTypeInferenceStateOnOOM* oom);
426 :
427 1351558 : uint32_t generation() {
428 1351558 : return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT;
429 : }
430 :
431 : public:
432 50907 : void setGeneration(uint32_t generation) {
433 50907 : MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT));
434 50907 : flags_ &= ~OBJECT_FLAG_GENERATION_MASK;
435 50907 : flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT;
436 50907 : }
437 :
438 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
439 :
440 : void finalize(FreeOp* fop);
441 :
442 : static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
443 :
444 132 : static inline uint32_t offsetOfClasp() {
445 132 : return offsetof(ObjectGroup, clasp_);
446 : }
447 :
448 102 : static inline uint32_t offsetOfProto() {
449 102 : return offsetof(ObjectGroup, proto_);
450 : }
451 :
452 17 : static inline uint32_t offsetOfCompartment() {
453 17 : return offsetof(ObjectGroup, compartment_);
454 : }
455 :
456 14 : static inline uint32_t offsetOfAddendum() {
457 14 : return offsetof(ObjectGroup, addendum_);
458 : }
459 :
460 302 : static inline uint32_t offsetOfFlags() {
461 302 : return offsetof(ObjectGroup, flags_);
462 : }
463 :
464 0 : const ObjectGroupFlags* addressOfFlags() const {
465 0 : return &flags_;
466 : }
467 :
468 : // Get the bit pattern stored in an object's addendum when it has an
469 : // original unboxed group.
470 151 : static inline int32_t addendumOriginalUnboxedGroupValue() {
471 151 : return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT;
472 : }
473 :
474 : inline uint32_t basePropertyCount();
475 :
476 : private:
477 : inline void setBasePropertyCount(uint32_t count);
478 :
479 : static void staticAsserts() {
480 : JS_STATIC_ASSERT(offsetof(ObjectGroup, proto_) == offsetof(js::shadow::ObjectGroup, proto));
481 : }
482 :
483 : public:
484 : // Whether to make a deep cloned singleton when cloning fun.
485 : static bool useSingletonForClone(JSFunction* fun);
486 :
487 : // Whether to make a singleton when calling 'new' at script/pc.
488 : static bool useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecode* pc);
489 :
490 : // Whether to make a singleton object at an allocation site.
491 : static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
492 : JSProtoKey key);
493 : static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
494 : const Class* clasp);
495 :
496 : // Static accessors for ObjectGroupCompartment NewTable.
497 :
498 : static ObjectGroup* defaultNewGroup(JSContext* cx, const Class* clasp,
499 : TaggedProto proto,
500 : JSObject* associated = nullptr);
501 : static ObjectGroup* lazySingletonGroup(JSContext* cx, const Class* clasp,
502 : TaggedProto proto);
503 :
504 : static void setDefaultNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
505 :
506 : #ifdef DEBUG
507 : static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
508 : #endif
509 :
510 : // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable.
511 :
512 : enum class NewArrayKind {
513 : Normal, // Specialize array group based on its element type.
514 : CopyOnWrite, // Make an array with copy-on-write elements.
515 : UnknownIndex // Make an array with an unknown element type.
516 : };
517 :
518 : // Create an ArrayObject or UnboxedArrayObject with the specified elements
519 : // and a group specialized for the elements.
520 : static JSObject* newArrayObject(JSContext* cx, const Value* vp, size_t length,
521 : NewObjectKind newKind,
522 : NewArrayKind arrayKind = NewArrayKind::Normal);
523 :
524 : // Create a PlainObject or UnboxedPlainObject with the specified properties
525 : // and a group specialized for those properties.
526 : static JSObject* newPlainObject(JSContext* cx,
527 : IdValuePair* properties, size_t nproperties,
528 : NewObjectKind newKind);
529 :
530 : // Static accessors for ObjectGroupCompartment AllocationSiteTable.
531 :
532 : // Get a non-singleton group to use for objects created at the specified
533 : // allocation site.
534 : static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
535 : JSProtoKey key, HandleObject proto = nullptr);
536 :
537 : // Get a non-singleton group to use for objects created in a JSNative call.
538 : static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key,
539 : HandleObject proto = nullptr);
540 :
541 : // Set the group or singleton-ness of an object created for an allocation site.
542 : static bool
543 : setAllocationSiteObjectGroup(JSContext* cx, HandleScript script, jsbytecode* pc,
544 : HandleObject obj, bool singleton);
545 :
546 : static ArrayObject* getOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script,
547 : jsbytecode* pc);
548 : static ArrayObject* getCopyOnWriteObject(JSScript* script, jsbytecode* pc);
549 :
550 : // Returns false if not found.
551 : static bool findAllocationSite(JSContext* cx, ObjectGroup* group,
552 : JSScript** script, uint32_t* offset);
553 :
554 : private:
555 : static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
556 : };
557 :
558 : // Structure used to manage the groups in a compartment.
559 : class ObjectGroupCompartment
560 : {
561 : friend class ObjectGroup;
562 :
563 : class NewTable;
564 :
565 : // Set of default 'new' or lazy groups in the compartment.
566 : NewTable* defaultNewTable;
567 : NewTable* lazyTable;
568 :
569 : // Cache for defaultNewGroup. Purged on GC.
570 : class DefaultNewGroupCache
571 : {
572 : ObjectGroup* group_;
573 : JSObject* associated_;
574 :
575 : public:
576 315 : DefaultNewGroupCache() { purge(); }
577 :
578 554 : void purge() {
579 554 : group_ = nullptr;
580 554 : }
581 36092 : void put(ObjectGroup* group, JSObject* associated) {
582 36092 : group_ = group;
583 36092 : associated_ = associated;
584 36092 : }
585 :
586 : MOZ_ALWAYS_INLINE ObjectGroup* lookup(const Class* clasp, TaggedProto proto,
587 : JSObject* associated);
588 : };
589 : DefaultNewGroupCache defaultNewGroupCache;
590 :
591 : struct ArrayObjectKey;
592 : using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
593 : ReadBarrieredObjectGroup,
594 : ArrayObjectKey,
595 : SystemAllocPolicy>;
596 :
597 : struct PlainObjectKey;
598 : struct PlainObjectEntry;
599 : struct PlainObjectTableSweepPolicy {
600 : static bool needsSweep(PlainObjectKey* key, PlainObjectEntry* entry);
601 : };
602 : using PlainObjectTable = JS::GCHashMap<PlainObjectKey,
603 : PlainObjectEntry,
604 : PlainObjectKey,
605 : SystemAllocPolicy,
606 : PlainObjectTableSweepPolicy>;
607 :
608 : // Tables for managing groups common to the contents of large script
609 : // singleton objects and JSON objects. These are vanilla ArrayObjects and
610 : // PlainObjects, so we distinguish the groups of different ones by looking
611 : // at the types of their properties.
612 : //
613 : // All singleton/JSON arrays which have the same prototype, are homogenous
614 : // and of the same element type will share a group. All singleton/JSON
615 : // objects which have the same shape and property types will also share a
616 : // group. We don't try to collate arrays or objects with type mismatches.
617 : ArrayObjectTable* arrayObjectTable;
618 : PlainObjectTable* plainObjectTable;
619 :
620 : struct AllocationSiteKey;
621 : class AllocationSiteTable;
622 :
623 : // Table for referencing types of objects keyed to an allocation site.
624 : AllocationSiteTable* allocationSiteTable;
625 :
626 : // A single per-compartment ObjectGroup for all calls to StringSplitString.
627 : // StringSplitString is always called from self-hosted code, and conceptually
628 : // the return object for a string.split(string) operation should have a
629 : // unified type. Having a global group for this also allows us to remove
630 : // the hash-table lookup that would be required if we allocated this group
631 : // on the basis of call-site pc.
632 : ReadBarrieredObjectGroup stringSplitStringGroup;
633 :
634 : public:
635 : struct NewEntry;
636 :
637 : ObjectGroupCompartment();
638 : ~ObjectGroupCompartment();
639 :
640 : void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
641 : JSProtoKey kind, ObjectGroup* group);
642 :
643 : void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated);
644 : void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated,
645 : ObjectGroup* group);
646 :
647 : static ObjectGroup* makeGroup(JSContext* cx, const Class* clasp,
648 : Handle<TaggedProto> proto,
649 : ObjectGroupFlags initialFlags = 0);
650 :
651 : static ObjectGroup* getStringSplitStringGroup(JSContext* cx);
652 :
653 : void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
654 : size_t* allocationSiteTables,
655 : size_t* arrayGroupTables,
656 : size_t* plainObjectGroupTables,
657 : size_t* compartmentTables);
658 :
659 : void clearTables();
660 :
661 : void sweep(FreeOp* fop);
662 :
663 223 : void purge() {
664 223 : defaultNewGroupCache.purge();
665 223 : }
666 :
667 : #ifdef JSGC_HASH_TABLE_CHECKS
668 0 : void checkTablesAfterMovingGC() {
669 0 : checkNewTableAfterMovingGC(defaultNewTable);
670 0 : checkNewTableAfterMovingGC(lazyTable);
671 0 : }
672 : #endif
673 :
674 0 : void fixupTablesAfterMovingGC() {
675 0 : fixupNewTableAfterMovingGC(defaultNewTable);
676 0 : fixupNewTableAfterMovingGC(lazyTable);
677 0 : }
678 :
679 : private:
680 : #ifdef JSGC_HASH_TABLE_CHECKS
681 : void checkNewTableAfterMovingGC(NewTable* table);
682 : #endif
683 :
684 : void fixupNewTableAfterMovingGC(NewTable* table);
685 : };
686 :
687 : PlainObject*
688 : NewPlainObjectWithProperties(JSContext* cx, IdValuePair* properties, size_t nproperties,
689 : NewObjectKind newKind);
690 :
691 : bool
692 : CombineArrayElementTypes(JSContext* cx, JSObject* newObj,
693 : const Value* compare, size_t ncompare);
694 :
695 : bool
696 : CombinePlainObjectPropertyTypes(JSContext* cx, JSObject* newObj,
697 : const Value* compare, size_t ncompare);
698 :
699 : } // namespace js
700 :
701 : #endif /* vm_ObjectGroup_h */
|