diff options
Diffstat (limited to 'js/src/gc/ObjectKind-inl.h')
-rw-r--r-- | js/src/gc/ObjectKind-inl.h | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/js/src/gc/ObjectKind-inl.h b/js/src/gc/ObjectKind-inl.h new file mode 100644 index 0000000000..d01680a5cf --- /dev/null +++ b/js/src/gc/ObjectKind-inl.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * GC-internal helper functions for getting the AllocKind used to allocate a + * JSObject and related information. + */ + +#ifndef gc_ObjectKind_inl_h +#define gc_ObjectKind_inl_h + +#include "util/Memory.h" +#include "vm/NativeObject.h" + +namespace js { +namespace gc { + +/* Capacity for slotsToThingKind */ +const size_t SLOTS_TO_THING_KIND_LIMIT = 17; +extern const AllocKind slotsToThingKind[]; +extern const uint32_t slotsToAllocKindBytes[]; + +/* Get the best kind to use when making an object with the given slot count. */ +static inline AllocKind GetGCObjectKind(size_t numSlots) { + if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) { + return AllocKind::OBJECT16; + } + return slotsToThingKind[numSlots]; +} + +static inline AllocKind GetGCObjectKind(const JSClass* clasp) { + MOZ_ASSERT(!clasp->isProxyObject(), + "Proxies should use GetProxyGCObjectKind"); + MOZ_ASSERT(!clasp->isJSFunction()); + + uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp); + return GetGCObjectKind(nslots); +} + +static constexpr bool CanUseFixedElementsForArray(size_t numElements) { + if (numElements > NativeObject::MAX_DENSE_ELEMENTS_COUNT) { + return false; + } + size_t numSlots = numElements + ObjectElements::VALUES_PER_HEADER; + return numSlots < SLOTS_TO_THING_KIND_LIMIT; +} + +/* As for GetGCObjectKind, but for dense array allocation. */ +static inline AllocKind GetGCArrayKind(size_t numElements) { + /* + * Dense arrays can use their fixed slots to hold their elements array + * (less two Values worth of ObjectElements header), but if more than the + * maximum number of fixed slots is needed then the fixed slots will be + * unused. + */ + static_assert(ObjectElements::VALUES_PER_HEADER == 2); + if (!CanUseFixedElementsForArray(numElements)) { + return AllocKind::OBJECT2; + } + return slotsToThingKind[numElements + ObjectElements::VALUES_PER_HEADER]; +} + +static inline AllocKind GetGCObjectFixedSlotsKind(size_t numFixedSlots) { + MOZ_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT); + return slotsToThingKind[numFixedSlots]; +} + +// Get the best kind to use when allocating an object that needs a specific +// number of bytes. +static inline AllocKind GetGCObjectKindForBytes(size_t nbytes) { + MOZ_ASSERT(nbytes <= JSObject::MAX_BYTE_SIZE); + + if (nbytes <= sizeof(NativeObject)) { + return AllocKind::OBJECT0; + } + nbytes -= sizeof(NativeObject); + + size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value); + MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value)); + return GetGCObjectKind(dataSlots); +} + +/* Get the number of fixed slots and initial capacity associated with a kind. */ +static constexpr inline size_t GetGCKindSlots(AllocKind thingKind) { + // Using a switch in hopes that thingKind will usually be a compile-time + // constant. + switch (thingKind) { + case AllocKind::OBJECT0: + case AllocKind::OBJECT0_BACKGROUND: + return 0; + case AllocKind::OBJECT2: + case AllocKind::OBJECT2_BACKGROUND: + return 2; + case AllocKind::FUNCTION: + case AllocKind::OBJECT4: + case AllocKind::OBJECT4_BACKGROUND: + return 4; + case AllocKind::FUNCTION_EXTENDED: + return 7; + case AllocKind::OBJECT8: + case AllocKind::OBJECT8_BACKGROUND: + return 8; + case AllocKind::OBJECT12: + case AllocKind::OBJECT12_BACKGROUND: + return 12; + case AllocKind::OBJECT16: + case AllocKind::OBJECT16_BACKGROUND: + return 16; + default: + MOZ_CRASH("Bad object alloc kind"); + } +} + +static inline size_t GetGCKindBytes(AllocKind thingKind) { + return sizeof(JSObject_Slots0) + GetGCKindSlots(thingKind) * sizeof(Value); +} + +static inline bool CanUseBackgroundAllocKind(const JSClass* clasp) { + return !clasp->hasFinalize() || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE); +} + +static inline bool CanChangeToBackgroundAllocKind(AllocKind kind, + const JSClass* clasp) { + // If a foreground alloc kind is specified but the class has no finalizer or a + // finalizer that is safe to call on a different thread, we can change the + // alloc kind to one which is finalized on a background thread. + // + // For example, AllocKind::OBJECT0 calls the finalizer on the main thread, and + // AllocKind::OBJECT0_BACKGROUND calls the finalizer on the a helper thread. + + MOZ_ASSERT(IsObjectAllocKind(kind)); + + if (IsBackgroundFinalized(kind)) { + return false; // This kind is already a background finalized kind. + } + + return CanUseBackgroundAllocKind(clasp); +} + +static inline AllocKind ForegroundToBackgroundAllocKind(AllocKind fgKind) { + MOZ_ASSERT(IsObjectAllocKind(fgKind)); + MOZ_ASSERT(IsForegroundFinalized(fgKind)); + + // For objects, each background alloc kind is defined just after the + // corresponding foreground alloc kind so we can convert between them by + // incrementing or decrementing as appropriate. + AllocKind bgKind = AllocKind(size_t(fgKind) + 1); + + MOZ_ASSERT(IsObjectAllocKind(bgKind)); + MOZ_ASSERT(IsBackgroundFinalized(bgKind)); + MOZ_ASSERT(GetGCKindSlots(bgKind) == GetGCKindSlots(fgKind)); + + return bgKind; +} + +} // namespace gc +} // namespace js + +#endif // gc_ObjectKind_inl_h |