mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Struct: keep direct reference to IMEMO/fields when space allows
It's not rare for structs to have additional ivars, hence are one of the most common, if not the most common type in the `gen_fields_tbl`. This can cause Ractor contention, but even in single ractor mode means having to do a hash lookup to access the ivars, and increase GC work. Instead, unless the struct is perfectly right sized, we can store a reference to the associated IMEMO/fields object right after the last struct member. ``` compare-ruby: ruby 3.5.0dev (2025-08-06T12:50:36Z struct-ivar-fields-2 9a30d141a1) +PRISM [arm64-darwin24] built-ruby: ruby 3.5.0dev (2025-08-06T12:57:59Z struct-ivar-fields-2 2ff3ec237f) +PRISM [arm64-darwin24] warming up..... | |compare-ruby|built-ruby| |:---------------------|-----------:|---------:| |member_reader | 590.317k| 579.246k| | | 1.02x| -| |member_writer | 543.963k| 527.104k| | | 1.03x| -| |member_reader_method | 213.540k| 213.004k| | | 1.00x| -| |member_writer_method | 192.657k| 191.491k| | | 1.01x| -| |ivar_reader | 403.993k| 569.915k| | | -| 1.41x| ``` Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
This commit is contained in:
parent
9b3ad3449b
commit
f3206cc79b
8 changed files with 194 additions and 23 deletions
|
@ -11,10 +11,23 @@
|
|||
#include "ruby/internal/stdbool.h" /* for bool */
|
||||
#include "ruby/ruby.h" /* for struct RBasic */
|
||||
|
||||
/* Flags of RStruct
|
||||
*
|
||||
* 1-7: RSTRUCT_EMBED_LEN
|
||||
* If non-zero, the struct is embedded (its contents follow the
|
||||
* header, rather than being on a separately allocated buffer) and
|
||||
* these bits are the length of the Struct.
|
||||
* 8: RSTRUCT_GEN_FIELDS
|
||||
* The struct is embedded and has no space left to store the
|
||||
* IMEMO/fields reference. Any ivar this struct may have will be in
|
||||
* the generic_fields_tbl. This flag doesn't imply the struct has
|
||||
* ivars.
|
||||
*/
|
||||
enum {
|
||||
RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 |
|
||||
RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1,
|
||||
RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
|
||||
RSTRUCT_GEN_FIELDS = RUBY_FL_USER8,
|
||||
};
|
||||
|
||||
struct RStruct {
|
||||
|
@ -23,6 +36,7 @@ struct RStruct {
|
|||
struct {
|
||||
long len;
|
||||
const VALUE *ptr;
|
||||
VALUE fields_obj;
|
||||
} heap;
|
||||
/* This is a length 1 array because:
|
||||
* 1. GCC has a bug that does not optimize C flexible array members
|
||||
|
@ -116,4 +130,31 @@ RSTRUCT_GET(VALUE st, long k)
|
|||
return RSTRUCT_CONST_PTR(st)[k];
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
RSTRUCT_FIELDS_OBJ(VALUE st)
|
||||
{
|
||||
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
||||
VALUE fields_obj;
|
||||
if (embed_len) {
|
||||
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
||||
fields_obj = RSTRUCT_GET(st, embed_len);
|
||||
}
|
||||
else {
|
||||
fields_obj = RSTRUCT(st)->as.heap.fields_obj;
|
||||
}
|
||||
return fields_obj;
|
||||
}
|
||||
|
||||
static inline void
|
||||
RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
|
||||
{
|
||||
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
||||
if (embed_len) {
|
||||
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
||||
RSTRUCT_SET(st, embed_len, fields_obj);
|
||||
}
|
||||
else {
|
||||
RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
|
||||
}
|
||||
}
|
||||
#endif /* INTERNAL_STRUCT_H */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue