Remove numiv from RObject
Since object shapes store the capacity of an object, we no longer need the numiv field on RObjects. This gives us one extra slot which we can use to give embedded objects one more instance variable (for a total of 3 ivs). This commit removes the concept of numiv from RObject.
This commit is contained in:
parent
5246f4027e
commit
c726c48a3d
Notes:
git
2022-11-10 15:12:04 +00:00
@ -515,7 +515,7 @@ dump_object(VALUE obj, struct dump_config *dc)
|
||||
|
||||
case T_OBJECT:
|
||||
dump_append(dc, ", \"ivars\":");
|
||||
dump_append_lu(dc, ROBJECT_NUMIV(obj));
|
||||
dump_append_lu(dc, ROBJECT_IV_CAPACITY(obj));
|
||||
break;
|
||||
|
||||
case T_FILE:
|
||||
|
22
gc.c
22
gc.c
@ -2943,14 +2943,9 @@ rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected)
|
||||
|
||||
VALUE obj = newobj_of(klass, flags, 0, 0, 0, wb_protected, size);
|
||||
|
||||
#if USE_RVARGC
|
||||
uint32_t capa = (uint32_t)((rb_gc_obj_slot_size(obj) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
|
||||
ROBJECT_SET_NUMIV(obj, capa);
|
||||
#endif
|
||||
|
||||
#if RUBY_DEBUG
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
for (size_t i = 0; i < ROBJECT_NUMIV(obj); i++) {
|
||||
for (size_t i = 0; i < ROBJECT_IV_CAPACITY(obj); i++) {
|
||||
ptr[i] = Qundef;
|
||||
}
|
||||
#endif
|
||||
@ -4859,7 +4854,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_OBJECT:
|
||||
if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
|
||||
size += ROBJECT_NUMIV(obj) * sizeof(VALUE);
|
||||
size += ROBJECT_IV_CAPACITY(obj) * sizeof(VALUE);
|
||||
}
|
||||
break;
|
||||
case T_MODULE:
|
||||
@ -8409,7 +8404,7 @@ gc_compact_destination_pool(rb_objspace_t *objspace, rb_size_pool_t *src_pool, V
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
obj_size = rb_obj_embedded_size(ROBJECT_NUMIV(src));
|
||||
obj_size = rb_obj_embedded_size(ROBJECT_IV_CAPACITY(src));
|
||||
break;
|
||||
|
||||
case T_STRING:
|
||||
@ -10019,7 +10014,7 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
|
||||
VALUE *ptr = ROBJECT_IVPTR(v);
|
||||
|
||||
#if USE_RVARGC
|
||||
uint32_t numiv = ROBJECT_NUMIV(v);
|
||||
uint32_t numiv = ROBJECT_IV_CAPACITY(v);
|
||||
|
||||
size_t slot_size = rb_gc_obj_slot_size(v);
|
||||
size_t embed_size = rb_obj_embedded_size(numiv);
|
||||
@ -10038,13 +10033,6 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
|
||||
rb_shape_t * initial_shape = rb_shape_get_shape_by_id((shape_id_t)size_pool_shape_id);
|
||||
rb_shape_t * new_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_shape(v));
|
||||
rb_shape_set_shape(v, new_shape);
|
||||
ROBJECT_SET_NUMIV(v, new_shape->capacity);
|
||||
#if RUBY_DEBUG
|
||||
if(RB_TYPE_P(v, T_OBJECT) && ROBJECT_IV_CAPACITY(v) != ROBJECT_NUMIV(v)) {
|
||||
fprintf(stderr, "shape capa: %d, v capa: %d\n", ROBJECT_IV_CAPACITY(v), ROBJECT_NUMIV(v));
|
||||
}
|
||||
#endif
|
||||
RUBY_ASSERT(!RB_TYPE_P(v, T_OBJECT) || ROBJECT_IV_CAPACITY(v) == ROBJECT_NUMIV(v));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -13975,7 +13963,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
|
||||
}
|
||||
case T_OBJECT:
|
||||
{
|
||||
uint32_t len = ROBJECT_NUMIV(obj);
|
||||
uint32_t len = ROBJECT_IV_CAPACITY(obj);
|
||||
|
||||
if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
|
||||
APPEND_F("(embed) len:%d", len);
|
||||
|
@ -44,7 +44,7 @@
|
||||
/** @cond INTERNAL_MACRO */
|
||||
#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
|
||||
#define ROBJECT_EMBED ROBJECT_EMBED
|
||||
#define ROBJECT_NUMIV ROBJECT_NUMIV
|
||||
#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY
|
||||
#define ROBJECT_IVPTR ROBJECT_IVPTR
|
||||
/** @endcond */
|
||||
|
||||
@ -96,14 +96,6 @@ struct RObject {
|
||||
/** Basic part, including flags and class. */
|
||||
struct RBasic basic;
|
||||
|
||||
#if USE_RVARGC
|
||||
/**
|
||||
* Number of instance variables. This is per object; objects might
|
||||
* differ in this field even if they have the identical classes.
|
||||
*/
|
||||
uint32_t numiv;
|
||||
#endif
|
||||
|
||||
/** Object's specific fields. */
|
||||
union {
|
||||
|
||||
@ -112,14 +104,6 @@ struct RObject {
|
||||
* this pattern.
|
||||
*/
|
||||
struct {
|
||||
#if !USE_RVARGC
|
||||
/**
|
||||
* Number of instance variables. This is per object; objects might
|
||||
* differ in this field even if they have the identical classes.
|
||||
*/
|
||||
uint32_t numiv;
|
||||
#endif
|
||||
|
||||
/** Pointer to a C array that holds instance variables. */
|
||||
VALUE *ivptr;
|
||||
|
||||
@ -156,52 +140,11 @@ struct RObject {
|
||||
|
||||
/* Offsets for YJIT */
|
||||
#ifndef __cplusplus
|
||||
# if USE_RVARGC
|
||||
static const int32_t ROBJECT_OFFSET_NUMIV = offsetof(struct RObject, numiv);
|
||||
# else
|
||||
static const int32_t ROBJECT_OFFSET_NUMIV = offsetof(struct RObject, as.heap.numiv);
|
||||
# endif
|
||||
static const int32_t ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr);
|
||||
static const int32_t ROBJECT_OFFSET_AS_HEAP_IV_INDEX_TBL = offsetof(struct RObject, as.heap.iv_index_tbl);
|
||||
static const int32_t ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary);
|
||||
#endif
|
||||
|
||||
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
/**
|
||||
* Queries the number of instance variables.
|
||||
*
|
||||
* @param[in] obj Object in question.
|
||||
* @return Its number of instance variables.
|
||||
* @pre `obj` must be an instance of ::RObject.
|
||||
*/
|
||||
static inline uint32_t
|
||||
ROBJECT_NUMIV(VALUE obj)
|
||||
{
|
||||
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
|
||||
|
||||
#if USE_RVARGC
|
||||
return ROBJECT(obj)->numiv;
|
||||
#else
|
||||
if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) {
|
||||
return ROBJECT_EMBED_LEN_MAX;
|
||||
}
|
||||
else {
|
||||
return ROBJECT(obj)->as.heap.numiv;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
ROBJECT_SET_NUMIV(VALUE obj, uint32_t capacity)
|
||||
{
|
||||
#if USE_RVARGC
|
||||
ROBJECT(obj)->numiv = capacity;
|
||||
#else
|
||||
ROBJECT(obj)->as.heap.numiv = capacity;
|
||||
#endif
|
||||
}
|
||||
|
||||
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
/**
|
||||
|
@ -386,7 +386,7 @@ module RubyVM::MJIT
|
||||
src << " dest_shape_id != ROBJECT_SHAPE_ID(obj)) {\n"
|
||||
# Conditionally generate a capacity change if there is one
|
||||
# between the destination and the parent IV set
|
||||
src << " rb_ensure_iv_list_size(obj, RBOJECT_NUMIV(obj), #{capa});\n" if capa
|
||||
src << " rb_ensure_iv_list_size(obj, ROBJECT_IV_CAPACITY(obj), #{capa});\n" if capa
|
||||
src << " ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);\n"
|
||||
src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n"
|
||||
src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n"
|
||||
|
1
object.c
1
object.c
@ -326,7 +326,6 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
||||
}
|
||||
|
||||
rb_shape_set_shape(dest, shape_to_set_on_dest);
|
||||
RUBY_ASSERT(!RB_TYPE_P(obj, T_OBJECT) || ROBJECT_IV_CAPACITY(dest) == ROBJECT_NUMIV(dest));
|
||||
}
|
||||
|
||||
static void
|
||||
|
20
variable.c
20
variable.c
@ -1346,7 +1346,7 @@ rb_obj_transient_heap_evacuate(VALUE obj, int promote)
|
||||
if (ROBJ_TRANSIENT_P(obj)) {
|
||||
assert(!RB_FL_TEST_RAW(obj, ROBJECT_EMBED));
|
||||
|
||||
uint32_t len = ROBJECT_NUMIV(obj);
|
||||
uint32_t len = ROBJECT_IV_CAPACITY(obj);
|
||||
const VALUE *old_ptr = ROBJECT_IVPTR(obj);
|
||||
VALUE *new_ptr;
|
||||
|
||||
@ -1378,7 +1378,6 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capaci
|
||||
else {
|
||||
newptr = obj_ivar_heap_realloc(obj, current_capacity, new_capacity);
|
||||
}
|
||||
ROBJECT_SET_NUMIV(obj, new_capacity);
|
||||
}
|
||||
|
||||
struct gen_ivtbl *
|
||||
@ -1405,21 +1404,14 @@ rb_ensure_generic_iv_list_size(VALUE obj, uint32_t newsize)
|
||||
rb_shape_t *
|
||||
rb_grow_iv_list(VALUE obj)
|
||||
{
|
||||
uint32_t len = ROBJECT_NUMIV(obj);
|
||||
rb_shape_t * initial_shape = rb_shape_get_shape(obj);
|
||||
uint32_t len = initial_shape->capacity;
|
||||
RUBY_ASSERT(len > 0);
|
||||
uint32_t newsize = (uint32_t)(len * 2);
|
||||
rb_ensure_iv_list_size(obj, len, newsize);
|
||||
rb_shape_t * res;
|
||||
|
||||
#if USE_RVARGC
|
||||
ROBJECT_SET_NUMIV(obj, newsize);
|
||||
#else
|
||||
ROBJECT(obj)->as.heap.numiv = newsize;
|
||||
#endif
|
||||
|
||||
res = rb_shape_transition_shape_capa(rb_shape_get_shape(obj), newsize);
|
||||
rb_shape_t * res = rb_shape_transition_shape_capa(initial_shape, newsize);
|
||||
rb_shape_set_shape(obj, res);
|
||||
RUBY_ASSERT(!RB_TYPE_P(obj, T_OBJECT) || ROBJECT_IV_CAPACITY(obj) == ROBJECT_NUMIV(obj));
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1437,12 +1429,10 @@ obj_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
found = false;
|
||||
}
|
||||
|
||||
uint32_t len = ROBJECT_NUMIV(obj);
|
||||
|
||||
// Reallocating can kick off GC. We can't set the new shape
|
||||
// on this object until the buffer has been allocated, otherwise
|
||||
// GC could read off the end of the buffer.
|
||||
if (len <= index) {
|
||||
if (shape->capacity <= index) {
|
||||
shape = rb_grow_iv_list(obj);
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ struct iseq_inline_constant_cache_entry {
|
||||
};
|
||||
STATIC_ASSERT(sizeof_iseq_inline_constant_cache_entry,
|
||||
(offsetof(struct iseq_inline_constant_cache_entry, ic_cref) +
|
||||
sizeof(const rb_cref_t *)) <= sizeof(struct RObject));
|
||||
sizeof(const rb_cref_t *)) <= RVALUE_SIZE);
|
||||
|
||||
struct iseq_inline_constant_cache {
|
||||
struct iseq_inline_constant_cache_entry *entry;
|
||||
|
@ -1301,8 +1301,8 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic,
|
||||
|
||||
attr_index_t index;
|
||||
|
||||
uint32_t num_iv = ROBJECT_NUMIV(obj);
|
||||
rb_shape_t* shape = rb_shape_get_shape(obj);
|
||||
uint32_t num_iv = shape->capacity;
|
||||
shape_id_t next_shape_id = ROBJECT_SHAPE_ID(obj);
|
||||
|
||||
if (!rb_shape_get_iv_index(shape, id, &index)) {
|
||||
@ -1446,13 +1446,11 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
|
||||
|
||||
if (shape_id == source_shape_id && dest_shape->edge_name == id) {
|
||||
RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
|
||||
RUBY_ASSERT(ROBJECT_IV_CAPACITY(obj) == ROBJECT_NUMIV(obj));
|
||||
|
||||
ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);
|
||||
|
||||
RUBY_ASSERT(rb_shape_get_next_iv_shape(rb_shape_get_shape_by_id(source_shape_id), id) == dest_shape);
|
||||
RUBY_ASSERT(ROBJECT_IV_CAPACITY(obj) == ROBJECT_NUMIV(obj));
|
||||
RUBY_ASSERT(index < ROBJECT_NUMIV(obj));
|
||||
RUBY_ASSERT(index < dest_shape->capacity);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
@ -2100,14 +2100,6 @@ fn gen_get_ivar(
|
||||
} else {
|
||||
// Compile time value is *not* embedded.
|
||||
|
||||
if USE_RVARGC == 0 {
|
||||
// Check that the extended table is big enough
|
||||
// Check that the slot is inside the extended table (num_slots > index)
|
||||
let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV);
|
||||
asm.cmp(num_slots, Opnd::UImm(ivar_index as u64));
|
||||
asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into());
|
||||
}
|
||||
|
||||
// Get a pointer to the extended table
|
||||
let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user