summaryrefslogtreecommitdiff
path: root/include/ruby/internal/core/rdata.h
diff options
context:
space:
mode:
authorJeremy Evans <[email protected]>2025-04-27 17:23:04 -0700
committerJeremy Evans <[email protected]>2025-05-05 09:46:32 +0900
commitce51ef30df5bf07ec3881a377f0011b8f20ec507 (patch)
tree27878fa2e8e428bcb43ca685f6904627fedc6080 /include/ruby/internal/core/rdata.h
parent35918df740018a510d0f9434e6eca2a2ad533003 (diff)
Save one VALUE per embedded RTypedData
This halves the amount of memory used for embedded RTypedData if they are one VALUE (8 bytes on 64-bit platforms) over the slot size limit. For Set, on 64-bit it uses an embedded 56-byte struct. With the previous implementation, the embedded structs starts at offset 32, resulting in a total size of 88. Since that is over the 80 byte limit, it goes to the next highest bucket, 160 bytes, wasting 72 bytes. This allows it to fit in a 80 byte bucket, which reduces the total size for small sets of from 224 bytes (160 bytes embedded, 64 bytes malloc, 72 bytes wasted in embedding) to 144 bytes (80 bytes embedded, 64 bytes malloc, 0 bytes wasted in embedding). Any other embedded RTypedData will see similar advantages if they are currently one VALUE over the limit. To implement this, remove the typed_flag from struct RTypedData. Embed the typed_flag information in the type member, which is now a tagged pointer using VALUE type, using the bottom low 2 bits as flags (1 bit for typed flag, the other for the embedded flag). To get the actual pointer, RTYPEDDATA_TYPE masks out the low 2 bits and then casts. That moves the RTypedData data pointer from offset 32 to offset 24 (on 64-bit). Vast amount of code in the internals (and probably external C extensions) expects the following code to work for both RData and non-embedded RTypedData: ```c DATA_PTR(obj) = some_pointer; ``` Allow this to work by moving the data pointer in RData between the dmark and dfree pointers, so it is at the same offset (24 on 64-bit). Other than these changes to the include files, the only changes needed were to gc.c, to account for the new struct layouts, handle setting the low bits in the type member, and to use RTYPEDDATA_TYPE(obj) instead of RTYPEDDATA(obj)->type.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/13190
Diffstat (limited to 'include/ruby/internal/core/rdata.h')
-rw-r--r--include/ruby/internal/core/rdata.h9
1 files changed, 6 insertions, 3 deletions
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index e4c146a716..cab412af72 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -133,6 +133,12 @@ struct RData {
*/
RUBY_DATA_FUNC dmark;
+ /** Pointer to the actual C level struct that you want to wrap.
+ * This is in between dmark and dfree to allow DATA_PTR to continue
+ * to work for both RData and non-embedded RTypedData.
+ */
+ void *data;
+
/**
* This function is called when the object is no longer used. You need to
* do whatever necessary to avoid memory leaks.
@@ -141,9 +147,6 @@ struct RData {
* impossible at that moment (that is why GC runs).
*/
RUBY_DATA_FUNC dfree;
-
- /** Pointer to the actual C level struct that you want to wrap. */
- void *data;
};
RBIMPL_SYMBOL_EXPORT_BEGIN()