summaryrefslogtreecommitdiffstats
path: root/js/src/gc/ObjectKind-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/gc/ObjectKind-inl.h')
-rw-r--r--js/src/gc/ObjectKind-inl.h162
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..a03b183447
--- /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[];
+
+/* 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 6;
+ 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