diff options
author | Jeremy Evans <[email protected]> | 2025-04-27 17:23:04 -0700 |
---|---|---|
committer | Jeremy Evans <[email protected]> | 2025-05-05 09:46:32 +0900 |
commit | ce51ef30df5bf07ec3881a377f0011b8f20ec507 (patch) | |
tree | 27878fa2e8e428bcb43ca685f6904627fedc6080 /include/ruby/internal/core/rdata.h | |
parent | 35918df740018a510d0f9434e6eca2a2ad533003 (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.h | 9 |
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() |