diff options
Diffstat (limited to 'include/ruby/internal/core/robject.h')
| -rw-r--r-- | include/ruby/internal/core/robject.h | 115 |
1 files changed, 83 insertions, 32 deletions
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index c352c87a40..df1901eb1e 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RObject. */ #include "ruby/internal/config.h" @@ -34,62 +34,113 @@ #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RObject. + * @return The passed object casted to ::RObject. + */ #define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj)) -#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX -#define ROBJECT_EMBED ROBJECT_EMBED /** @cond INTERNAL_MACRO */ -#define ROBJECT_NUMIV ROBJECT_NUMIV -#define ROBJECT_IVPTR ROBJECT_IVPTR -#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL +#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX +#define ROBJECT_HEAP ROBJECT_HEAP +#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY +#define ROBJECT_FIELDS ROBJECT_FIELDS /** @endcond */ -enum ruby_robject_flags { ROBJECT_EMBED = RUBY_FL_USER1 }; - -enum ruby_robject_consts { ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE) }; +/** + * @private + * + * Bits that you can set to ::RBasic::flags. + */ +enum ruby_robject_flags { + /** + * This flag marks that the object's instance variables are stored in an + * external heap buffer. + * Normally, instance variable references are stored inside the object slot, + * but if it overflow, Ruby may have to allocate a separate buffer and spills + * the instance variables there. + * This flag denotes that situation. + * + * @warning This bit has to be considered read-only. Setting/clearing + * this bit without corresponding fix up must cause immediate + * SEGV. Also, internal structures of an object change + * dynamically and transparently throughout of its lifetime. + * Don't assume it being persistent. + * + * @internal + * + * 3rd parties must not be aware that there even is more than one way to + * store instance variables. Might better be hidden. + */ + ROBJECT_HEAP = RUBY_FL_USER4 +}; struct st_table; +/** + * Ruby's ordinal objects. Unless otherwise special cased, all predefined and + * user-defined classes share this struct to hold their instances. + */ struct RObject { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** Object's specific fields. */ union { + + /** + * Object that use separated memory region for instance variables use + * this pattern. + */ struct { - uint32_t numiv; - VALUE *ivptr; - struct st_table *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */ + /** Pointer to a C array that holds instance variables. */ + VALUE *fields; } heap; - VALUE ary[ROBJECT_EMBED_LEN_MAX]; - } as; -}; -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -static inline uint32_t -ROBJECT_NUMIV(VALUE obj) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + /* When an object is too complex, it uses a st_table to store instance + * variable name to value mappings. + */ + st_table *hash; - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - return ROBJECT_EMBED_LEN_MAX; - } - else { - return ROBJECT(obj)->as.heap.numiv; - } -} + /* Embedded instance variables. When an object is small enough, it + * uses this area to store the instance variables. + * + * This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + VALUE ary[1]; + } as; +}; RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the instance variables. + * + * @param[in] obj Object in question. + * @return Its instance variables, in C array. + * @pre `obj` must be an instance of ::RObject. + * + * @internal + * + * @shyouhei finds no reason for this to be visible from extension libraries. + */ static inline VALUE * -ROBJECT_IVPTR(VALUE obj) +ROBJECT_FIELDS(VALUE obj) { RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); struct RObject *const ptr = ROBJECT(obj); - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - return ptr->as.ary; + if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) { + return ptr->as.heap.fields; } else { - return ptr->as.heap.ivptr; + return ptr->as.ary; } } |
