Rename ivptr
-> fields
, next_iv_index
-> next_field_index
Ivars will longer be the only thing stored inline via shapes, so keeping the `iv_index` and `ivptr` names would be confusing. Instance variables won't be the only thing stored inline via shapes, so keeping the `ivptr` name would be confusing. `field` encompass anything that can be stored in a VALUE array. Similarly, `gen_ivtbl` becomes `gen_fields_tbl`.
This commit is contained in:
parent
4e30b77b90
commit
0ea210d1ea
Notes:
git
2025-05-08 05:58:20 +00:00
@ -1595,7 +1595,7 @@ assert_equal "ok", %Q{
|
||||
:ok
|
||||
}
|
||||
|
||||
# Generic ivtbl
|
||||
# Generic fields_tbl
|
||||
n = N/2
|
||||
assert_equal "#{n}#{n}", %Q{
|
||||
2.times.map{
|
||||
|
6
class.c
6
class.c
@ -249,7 +249,7 @@ class_alloc(VALUE flags, VALUE klass)
|
||||
/* ZALLOC
|
||||
RCLASS_CONST_TBL(obj) = 0;
|
||||
RCLASS_M_TBL(obj) = 0;
|
||||
RCLASS_IV_INDEX_TBL(obj) = 0;
|
||||
RCLASS_FIELDS(obj) = 0;
|
||||
RCLASS_SET_SUPER((VALUE)obj, 0);
|
||||
RCLASS_SUBCLASSES(obj) = NULL;
|
||||
RCLASS_PARENT_SUBCLASSES(obj) = NULL;
|
||||
@ -485,7 +485,7 @@ copy_tables(VALUE clone, VALUE orig)
|
||||
if (!RB_TYPE_P(clone, T_ICLASS)) {
|
||||
st_data_t id;
|
||||
|
||||
rb_iv_tbl_copy(clone, orig);
|
||||
rb_fields_tbl_copy(clone, orig);
|
||||
CONST_ID(id, "__tmp_classpath__");
|
||||
rb_attr_delete(clone, id);
|
||||
CONST_ID(id, "__classpath__");
|
||||
@ -679,7 +679,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
|
||||
}
|
||||
|
||||
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
|
||||
rb_iv_tbl_copy(clone, klass);
|
||||
rb_fields_tbl_copy(clone, klass);
|
||||
if (RCLASS_CONST_TBL(klass)) {
|
||||
struct clone_const_arg arg;
|
||||
arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
|
||||
|
@ -586,7 +586,7 @@ dump_object(VALUE obj, struct dump_config *dc)
|
||||
}
|
||||
|
||||
dump_append(dc, ", \"ivars\":");
|
||||
dump_append_lu(dc, ROBJECT_IV_COUNT(obj));
|
||||
dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
dump_append(dc, ", \"too_complex_shape\":true");
|
||||
}
|
||||
|
98
gc.c
98
gc.c
@ -1267,13 +1267,13 @@ rb_gc_obj_free(void *objspace, VALUE obj)
|
||||
case T_OBJECT:
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
|
||||
st_free_table(ROBJECT_IV_HASH(obj));
|
||||
st_free_table(ROBJECT_FIELDS_HASH(obj));
|
||||
}
|
||||
else if (RBASIC(obj)->flags & ROBJECT_EMBED) {
|
||||
RB_DEBUG_COUNTER_INC(obj_obj_embed);
|
||||
}
|
||||
else {
|
||||
xfree(ROBJECT(obj)->as.heap.ivptr);
|
||||
xfree(ROBJECT(obj)->as.heap.fields);
|
||||
RB_DEBUG_COUNTER_INC(obj_obj_ptr);
|
||||
}
|
||||
break;
|
||||
@ -1282,10 +1282,10 @@ rb_gc_obj_free(void *objspace, VALUE obj)
|
||||
rb_id_table_free(RCLASS_M_TBL(obj));
|
||||
rb_cc_table_free(obj);
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
st_free_table((st_table *)RCLASS_IVPTR(obj));
|
||||
st_free_table((st_table *)RCLASS_FIELDS(obj));
|
||||
}
|
||||
else {
|
||||
xfree(RCLASS_IVPTR(obj));
|
||||
xfree(RCLASS_FIELDS(obj));
|
||||
}
|
||||
|
||||
if (RCLASS_CONST_TBL(obj)) {
|
||||
@ -1925,10 +1925,10 @@ rb_obj_memsize_of(VALUE obj)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_OBJECT:
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
size += rb_st_memsize(ROBJECT_IV_HASH(obj));
|
||||
size += rb_st_memsize(ROBJECT_FIELDS_HASH(obj));
|
||||
}
|
||||
else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
|
||||
size += ROBJECT_IV_CAPACITY(obj) * sizeof(VALUE);
|
||||
size += ROBJECT_FIELDS_CAPACITY(obj) * sizeof(VALUE);
|
||||
}
|
||||
break;
|
||||
case T_MODULE:
|
||||
@ -1937,7 +1937,7 @@ rb_obj_memsize_of(VALUE obj)
|
||||
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
|
||||
}
|
||||
// class IV sizes are allocated as powers of two
|
||||
size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
|
||||
size += SIZEOF_VALUE << bit_length(RCLASS_FIELDS_COUNT(obj));
|
||||
if (RCLASS_CVC_TBL(obj)) {
|
||||
size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
|
||||
}
|
||||
@ -2713,11 +2713,11 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
||||
mark_cvc_tbl(objspace, obj);
|
||||
rb_cc_table_mark(obj);
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
gc_mark_tbl_no_pin((st_table *)RCLASS_IVPTR(obj));
|
||||
gc_mark_tbl_no_pin((st_table *)RCLASS_FIELDS(obj));
|
||||
}
|
||||
else {
|
||||
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
|
||||
gc_mark_internal(RCLASS_IVPTR(obj)[i]);
|
||||
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
|
||||
gc_mark_internal(RCLASS_FIELDS(obj)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2802,12 +2802,12 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
||||
rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
gc_mark_tbl_no_pin(ROBJECT_IV_HASH(obj));
|
||||
gc_mark_tbl_no_pin(ROBJECT_FIELDS_HASH(obj));
|
||||
}
|
||||
else {
|
||||
const VALUE * const ptr = ROBJECT_IVPTR(obj);
|
||||
const VALUE * const ptr = ROBJECT_FIELDS(obj);
|
||||
|
||||
uint32_t len = ROBJECT_IV_COUNT(obj);
|
||||
uint32_t len = ROBJECT_FIELDS_COUNT(obj);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
gc_mark_internal(ptr[i]);
|
||||
}
|
||||
@ -2817,7 +2817,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
||||
VALUE klass = RBASIC_CLASS(obj);
|
||||
|
||||
// Increment max_iv_count if applicable, used to determine size pool allocation
|
||||
attr_index_t num_of_ivs = shape->next_iv_index;
|
||||
attr_index_t num_of_ivs = shape->next_field_index;
|
||||
if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) {
|
||||
RCLASS_EXT(klass)->max_iv_count = num_of_ivs;
|
||||
}
|
||||
@ -2893,7 +2893,7 @@ rb_gc_obj_optimal_size(VALUE obj)
|
||||
return sizeof(struct RObject);
|
||||
}
|
||||
else {
|
||||
return rb_obj_embedded_size(ROBJECT_IV_CAPACITY(obj));
|
||||
return rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj));
|
||||
}
|
||||
|
||||
case T_STRING:
|
||||
@ -3129,24 +3129,24 @@ gc_ref_update_array(void *objspace, VALUE v)
|
||||
static void
|
||||
gc_ref_update_object(void *objspace, VALUE v)
|
||||
{
|
||||
VALUE *ptr = ROBJECT_IVPTR(v);
|
||||
VALUE *ptr = ROBJECT_FIELDS(v);
|
||||
|
||||
if (rb_shape_obj_too_complex(v)) {
|
||||
gc_ref_update_table_values_only(ROBJECT_IV_HASH(v));
|
||||
gc_ref_update_table_values_only(ROBJECT_FIELDS_HASH(v));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t slot_size = rb_gc_obj_slot_size(v);
|
||||
size_t embed_size = rb_obj_embedded_size(ROBJECT_IV_CAPACITY(v));
|
||||
size_t embed_size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(v));
|
||||
if (slot_size >= embed_size && !RB_FL_TEST_RAW(v, ROBJECT_EMBED)) {
|
||||
// Object can be re-embedded
|
||||
memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_IV_COUNT(v));
|
||||
memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_FIELDS_COUNT(v));
|
||||
RB_FL_SET_RAW(v, ROBJECT_EMBED);
|
||||
xfree(ptr);
|
||||
ptr = ROBJECT(v)->as.ary;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ROBJECT_IV_COUNT(v); i++) {
|
||||
for (uint32_t i = 0; i < ROBJECT_FIELDS_COUNT(v); i++) {
|
||||
UPDATE_IF_MOVED(objspace, ptr[i]);
|
||||
}
|
||||
}
|
||||
@ -3427,17 +3427,17 @@ vm_weak_table_foreach_update_weak_value(st_data_t *key, st_data_t *value, st_dat
|
||||
}
|
||||
|
||||
static void
|
||||
free_gen_ivtbl(VALUE obj, struct gen_ivtbl *ivtbl)
|
||||
free_gen_fields_tbl(VALUE obj, struct gen_fields_tbl *fields_tbl)
|
||||
{
|
||||
if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
|
||||
st_free_table(ivtbl->as.complex.table);
|
||||
st_free_table(fields_tbl->as.complex.table);
|
||||
}
|
||||
|
||||
xfree(ivtbl);
|
||||
xfree(fields_tbl);
|
||||
}
|
||||
|
||||
static int
|
||||
vm_weak_table_gen_ivar_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error)
|
||||
vm_weak_table_gen_fields_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error)
|
||||
{
|
||||
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
|
||||
|
||||
@ -3449,7 +3449,7 @@ vm_weak_table_gen_ivar_foreach_too_complex_i(st_data_t _key, st_data_t value, st
|
||||
}
|
||||
|
||||
static int
|
||||
vm_weak_table_gen_ivar_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing)
|
||||
vm_weak_table_gen_fields_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing)
|
||||
{
|
||||
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
|
||||
|
||||
@ -3458,10 +3458,10 @@ vm_weak_table_gen_ivar_foreach_too_complex_replace_i(st_data_t *_key, st_data_t
|
||||
return iter_data->update_callback((VALUE *)value, iter_data->data);
|
||||
}
|
||||
|
||||
struct st_table *rb_generic_ivtbl_get(void);
|
||||
struct st_table *rb_generic_fields_tbl_get(void);
|
||||
|
||||
static int
|
||||
vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
|
||||
vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
|
||||
{
|
||||
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
|
||||
|
||||
@ -3472,7 +3472,7 @@ vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
|
||||
break;
|
||||
|
||||
case ST_DELETE:
|
||||
free_gen_ivtbl((VALUE)key, (struct gen_ivtbl *)value);
|
||||
free_gen_fields_tbl((VALUE)key, (struct gen_fields_tbl *)value);
|
||||
|
||||
FL_UNSET((VALUE)key, FL_EXIVAR);
|
||||
return ST_DELETE;
|
||||
@ -3483,7 +3483,7 @@ vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
|
||||
if (key != new_key) ret = ST_DELETE;
|
||||
DURING_GC_COULD_MALLOC_REGION_START();
|
||||
{
|
||||
st_insert(rb_generic_ivtbl_get(), (st_data_t)new_key, value);
|
||||
st_insert(rb_generic_fields_tbl_get(), (st_data_t)new_key, value);
|
||||
}
|
||||
DURING_GC_COULD_MALLOC_REGION_END();
|
||||
key = (st_data_t)new_key;
|
||||
@ -3495,29 +3495,29 @@ vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
|
||||
}
|
||||
|
||||
if (!iter_data->weak_only) {
|
||||
struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
|
||||
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value;
|
||||
|
||||
if (rb_shape_obj_too_complex((VALUE)key)) {
|
||||
st_foreach_with_replace(
|
||||
ivtbl->as.complex.table,
|
||||
vm_weak_table_gen_ivar_foreach_too_complex_i,
|
||||
vm_weak_table_gen_ivar_foreach_too_complex_replace_i,
|
||||
fields_tbl->as.complex.table,
|
||||
vm_weak_table_gen_fields_foreach_too_complex_i,
|
||||
vm_weak_table_gen_fields_foreach_too_complex_replace_i,
|
||||
data
|
||||
);
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (SPECIAL_CONST_P(ivtbl->as.shape.ivptr[i])) continue;
|
||||
for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
|
||||
if (SPECIAL_CONST_P(fields_tbl->as.shape.fields[i])) continue;
|
||||
|
||||
int ivar_ret = iter_data->callback(ivtbl->as.shape.ivptr[i], iter_data->data);
|
||||
int ivar_ret = iter_data->callback(fields_tbl->as.shape.fields[i], iter_data->data);
|
||||
switch (ivar_ret) {
|
||||
case ST_CONTINUE:
|
||||
break;
|
||||
case ST_REPLACE:
|
||||
iter_data->update_callback(&ivtbl->as.shape.ivptr[i], iter_data->data);
|
||||
iter_data->update_callback(&fields_tbl->as.shape.fields[i], iter_data->data);
|
||||
break;
|
||||
default:
|
||||
rb_bug("vm_weak_table_gen_ivar_foreach: return value %d not supported", ivar_ret);
|
||||
rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3587,12 +3587,12 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RB_GC_VM_GENERIC_IV_TABLE: {
|
||||
st_table *generic_iv_tbl = rb_generic_ivtbl_get();
|
||||
if (generic_iv_tbl) {
|
||||
case RB_GC_VM_GENERIC_FIELDS_TABLE: {
|
||||
st_table *generic_fields_tbl = rb_generic_fields_tbl_get();
|
||||
if (generic_fields_tbl) {
|
||||
st_foreach(
|
||||
generic_iv_tbl,
|
||||
vm_weak_table_gen_ivar_foreach,
|
||||
generic_fields_tbl,
|
||||
vm_weak_table_gen_fields_foreach,
|
||||
(st_data_t)&foreach_data
|
||||
);
|
||||
}
|
||||
@ -3649,11 +3649,11 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
|
||||
update_superclasses(objspace, obj);
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
gc_ref_update_table_values_only(RCLASS_IV_HASH(obj));
|
||||
gc_ref_update_table_values_only(RCLASS_FIELDS_HASH(obj));
|
||||
}
|
||||
else {
|
||||
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
|
||||
UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
|
||||
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
|
||||
UPDATE_IF_MOVED(objspace, RCLASS_FIELDS(obj)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4336,17 +4336,17 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
|
||||
case T_OBJECT:
|
||||
{
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
size_t hash_len = rb_st_table_size(ROBJECT_IV_HASH(obj));
|
||||
size_t hash_len = rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
|
||||
APPEND_F("(too_complex) len:%zu", hash_len);
|
||||
}
|
||||
else {
|
||||
uint32_t len = ROBJECT_IV_CAPACITY(obj);
|
||||
uint32_t len = ROBJECT_FIELDS_CAPACITY(obj);
|
||||
|
||||
if (RBASIC(obj)->flags & ROBJECT_EMBED) {
|
||||
APPEND_F("(embed) len:%d", len);
|
||||
}
|
||||
else {
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
VALUE *ptr = ROBJECT_FIELDS(obj);
|
||||
APPEND_F("len:%d ptr:%p", len, (void *)ptr);
|
||||
}
|
||||
}
|
||||
|
2
gc/gc.h
2
gc/gc.h
@ -28,7 +28,7 @@ enum rb_gc_vm_weak_tables {
|
||||
RB_GC_VM_CI_TABLE,
|
||||
RB_GC_VM_OVERLOADED_CME_TABLE,
|
||||
RB_GC_VM_GLOBAL_SYMBOLS_TABLE,
|
||||
RB_GC_VM_GENERIC_IV_TABLE,
|
||||
RB_GC_VM_GENERIC_FIELDS_TABLE,
|
||||
RB_GC_VM_FROZEN_STRINGS_TABLE,
|
||||
RB_GC_VM_WEAK_TABLE_COUNT
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ pub const MIN_OBJ_ALIGN: usize = 8; // Even on 32-bit machine. A Ruby object is
|
||||
|
||||
pub const GC_THREAD_KIND_WORKER: libc::c_int = 1;
|
||||
|
||||
const HAS_MOVED_GIVTBL: usize = 1 << 63;
|
||||
const HAS_MOVED_GFIELDSTBL: usize = 1 << 63;
|
||||
const HIDDEN_SIZE_MASK: usize = 0x0000FFFFFFFFFFFF;
|
||||
|
||||
// Should keep in sync with C code.
|
||||
@ -87,16 +87,16 @@ impl RubyObjectAccess {
|
||||
(self.load_flags() & RUBY_FL_EXIVAR) != 0
|
||||
}
|
||||
|
||||
pub fn has_moved_givtbl(&self) -> bool {
|
||||
(self.load_hidden_field() & HAS_MOVED_GIVTBL) != 0
|
||||
pub fn has_moved_gfields_tbl(&self) -> bool {
|
||||
(self.load_hidden_field() & HAS_MOVED_GFIELDSTBL) != 0
|
||||
}
|
||||
|
||||
pub fn set_has_moved_givtbl(&self) {
|
||||
self.update_hidden_field(|old| old | HAS_MOVED_GIVTBL)
|
||||
pub fn set_has_moved_gfields_tbl(&self) {
|
||||
self.update_hidden_field(|old| old | HAS_MOVED_GFIELDSTBL)
|
||||
}
|
||||
|
||||
pub fn clear_has_moved_givtbl(&self) {
|
||||
self.update_hidden_field(|old| old & !HAS_MOVED_GIVTBL)
|
||||
pub fn clear_has_moved_gfields_tbl(&self) {
|
||||
self.update_hidden_field(|old| old & !HAS_MOVED_GFIELDSTBL)
|
||||
}
|
||||
|
||||
pub fn prefix_size() -> usize {
|
||||
|
@ -23,7 +23,7 @@
|
||||
* who is implementing the internals) could have used those macros for a while.
|
||||
* Kept public as-is here to keep some theoretical backwards compatibility.
|
||||
*/
|
||||
#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
|
||||
#define RMODULE_IV_TBL(m) RCLASS_FIELDS(m)
|
||||
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
|
||||
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
|
||||
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
|
||||
|
@ -42,10 +42,10 @@
|
||||
*/
|
||||
#define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj))
|
||||
/** @cond INTERNAL_MACRO */
|
||||
#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
|
||||
#define ROBJECT_EMBED ROBJECT_EMBED
|
||||
#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY
|
||||
#define ROBJECT_IVPTR ROBJECT_IVPTR
|
||||
#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
|
||||
#define ROBJECT_EMBED ROBJECT_EMBED
|
||||
#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY
|
||||
#define ROBJECT_FIELDS ROBJECT_FIELDS
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
@ -94,7 +94,7 @@ struct RObject {
|
||||
*/
|
||||
struct {
|
||||
/** Pointer to a C array that holds instance variables. */
|
||||
VALUE *ivptr;
|
||||
VALUE *fields;
|
||||
} heap;
|
||||
|
||||
/* Embedded instance variables. When an object is small enough, it
|
||||
@ -123,7 +123,7 @@ RBIMPL_ATTR_ARTIFICIAL()
|
||||
* @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);
|
||||
|
||||
@ -133,7 +133,7 @@ ROBJECT_IVPTR(VALUE obj)
|
||||
return ptr->as.ary;
|
||||
}
|
||||
else {
|
||||
return ptr->as.heap.ivptr;
|
||||
return ptr->as.heap.fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ struct rb_cvar_class_tbl_entry {
|
||||
};
|
||||
|
||||
struct rb_classext_struct {
|
||||
VALUE *iv_ptr;
|
||||
VALUE *fields; // Fields are either ivar or other internal properties stored inline
|
||||
struct rb_id_table *const_tbl;
|
||||
struct rb_id_table *callable_m_tbl;
|
||||
struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */
|
||||
@ -94,7 +94,7 @@ struct RClass_and_rb_classext_t {
|
||||
#define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
|
||||
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
|
||||
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
||||
#define RCLASS_IVPTR(c) (RCLASS_EXT(c)->iv_ptr)
|
||||
#define RCLASS_FIELDS(c) (RCLASS_EXT(c)->fields)
|
||||
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
|
||||
#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
|
||||
#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl)
|
||||
@ -114,23 +114,23 @@ struct RClass_and_rb_classext_t {
|
||||
#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3
|
||||
|
||||
static inline st_table *
|
||||
RCLASS_IV_HASH(VALUE obj)
|
||||
RCLASS_FIELDS_HASH(VALUE obj)
|
||||
{
|
||||
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
return (st_table *)RCLASS_IVPTR(obj);
|
||||
return (st_table *)RCLASS_FIELDS(obj);
|
||||
}
|
||||
|
||||
static inline void
|
||||
RCLASS_SET_IV_HASH(VALUE obj, const st_table *tbl)
|
||||
RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
|
||||
{
|
||||
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
RCLASS_IVPTR(obj) = (VALUE *)tbl;
|
||||
RCLASS_FIELDS(obj) = (VALUE *)tbl;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
RCLASS_IV_COUNT(VALUE obj)
|
||||
RCLASS_FIELDS_COUNT(VALUE obj)
|
||||
{
|
||||
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
@ -140,14 +140,14 @@ RCLASS_IV_COUNT(VALUE obj)
|
||||
// parallel, so lets lock around getting the hash size.
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
count = (uint32_t)rb_st_table_size(RCLASS_IV_HASH(obj));
|
||||
count = (uint32_t)rb_st_table_size(RCLASS_FIELDS_HASH(obj));
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
return count;
|
||||
}
|
||||
else {
|
||||
return rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
|
||||
return rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_field_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "ruby/ruby.h" /* for VALUE */
|
||||
|
||||
/* object.c */
|
||||
size_t rb_obj_embedded_size(uint32_t numiv);
|
||||
size_t rb_obj_embedded_size(uint32_t fields_count);
|
||||
VALUE rb_class_allocate_instance(VALUE klass);
|
||||
VALUE rb_class_search_ancestor(VALUE klass, VALUE super);
|
||||
NORETURN(void rb_undefined_alloc(VALUE klass));
|
||||
|
@ -45,8 +45,8 @@ void rb_gvar_ractor_local(const char *name);
|
||||
*/
|
||||
VALUE rb_mod_set_temporary_name(VALUE, VALUE);
|
||||
|
||||
struct gen_ivtbl;
|
||||
int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl);
|
||||
struct gen_fields_tbl;
|
||||
int rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl);
|
||||
void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
|
||||
void rb_obj_convert_to_too_complex(VALUE obj, st_table *table);
|
||||
void rb_evict_ivars_to_hash(VALUE obj);
|
||||
@ -56,7 +56,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
|
||||
void rb_mark_generic_ivar(VALUE obj);
|
||||
VALUE rb_const_missing(VALUE klass, VALUE name);
|
||||
int rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
|
||||
void rb_iv_tbl_copy(VALUE dst, VALUE src);
|
||||
void rb_fields_tbl_copy(VALUE dst, VALUE src);
|
||||
RUBY_SYMBOL_EXPORT_END
|
||||
|
||||
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
|
||||
|
18
object.c
18
object.c
@ -95,9 +95,9 @@ static VALUE rb_cFalseClass_to_s;
|
||||
/*! \endcond */
|
||||
|
||||
size_t
|
||||
rb_obj_embedded_size(uint32_t numiv)
|
||||
rb_obj_embedded_size(uint32_t fields_count)
|
||||
{
|
||||
return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
|
||||
return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
|
||||
}
|
||||
|
||||
VALUE
|
||||
@ -139,8 +139,8 @@ rb_class_allocate_instance(VALUE klass)
|
||||
|
||||
#if RUBY_DEBUG
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
for (size_t i = 0; i < ROBJECT_IV_CAPACITY(obj); i++) {
|
||||
VALUE *ptr = ROBJECT_FIELDS(obj);
|
||||
for (size_t i = 0; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
|
||||
ptr[i] = Qundef;
|
||||
}
|
||||
#endif
|
||||
@ -333,13 +333,13 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
// obj is TOO_COMPLEX so we can copy its iv_hash
|
||||
st_table *table = st_copy(ROBJECT_IV_HASH(obj));
|
||||
st_table *table = st_copy(ROBJECT_FIELDS_HASH(obj));
|
||||
rb_obj_convert_to_too_complex(dest, table);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t src_num_ivs = RBASIC_IV_COUNT(obj);
|
||||
uint32_t src_num_ivs = RBASIC_FIELDS_COUNT(obj);
|
||||
rb_shape_t *shape_to_set_on_dest = src_shape;
|
||||
VALUE * src_buf;
|
||||
VALUE * dest_buf;
|
||||
@ -353,8 +353,8 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
||||
shape_to_set_on_dest = rb_shape_get_parent(src_shape);
|
||||
}
|
||||
|
||||
src_buf = ROBJECT_IVPTR(obj);
|
||||
dest_buf = ROBJECT_IVPTR(dest);
|
||||
src_buf = ROBJECT_FIELDS(obj);
|
||||
dest_buf = ROBJECT_FIELDS(dest);
|
||||
|
||||
rb_shape_t *initial_shape = rb_shape_get_shape(dest);
|
||||
|
||||
@ -374,7 +374,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
||||
RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
|
||||
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
|
||||
dest_buf = ROBJECT_IVPTR(dest);
|
||||
dest_buf = ROBJECT_FIELDS(dest);
|
||||
}
|
||||
|
||||
MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs);
|
||||
|
18
ractor.c
18
ractor.c
@ -3358,8 +3358,8 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
} while (0)
|
||||
|
||||
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
rb_ivar_generic_fields_tbl_lookup(obj, &fields_tbl);
|
||||
|
||||
if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
|
||||
struct obj_traverse_replace_callback_data d = {
|
||||
@ -3368,7 +3368,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
.src = obj,
|
||||
};
|
||||
rb_st_foreach_with_replace(
|
||||
ivtbl->as.complex.table,
|
||||
fields_tbl->as.complex.table,
|
||||
obj_iv_hash_traverse_replace_foreach_i,
|
||||
obj_iv_hash_traverse_replace_i,
|
||||
(st_data_t)&d
|
||||
@ -3376,9 +3376,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
if (d.stop) return 1;
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
|
||||
CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
|
||||
for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
|
||||
if (!UNDEF_P(fields_tbl->as.shape.fields[i])) {
|
||||
CHECK_AND_REPLACE(fields_tbl->as.shape.fields[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3406,7 +3406,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
.src = obj,
|
||||
};
|
||||
rb_st_foreach_with_replace(
|
||||
ROBJECT_IV_HASH(obj),
|
||||
ROBJECT_FIELDS_HASH(obj),
|
||||
obj_iv_hash_traverse_replace_foreach_i,
|
||||
obj_iv_hash_traverse_replace_i,
|
||||
(st_data_t)&d
|
||||
@ -3414,8 +3414,8 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||
if (d.stop) return 1;
|
||||
}
|
||||
else {
|
||||
uint32_t len = ROBJECT_IV_COUNT(obj);
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
uint32_t len = ROBJECT_FIELDS_COUNT(obj);
|
||||
VALUE *ptr = ROBJECT_FIELDS(obj);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
CHECK_AND_REPLACE(ptr[i]);
|
||||
|
66
shape.c
66
shape.c
@ -406,7 +406,7 @@ rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
|
||||
rb_shape_t *shape = shape_alloc();
|
||||
|
||||
shape->edge_name = edge_name;
|
||||
shape->next_iv_index = 0;
|
||||
shape->next_field_index = 0;
|
||||
shape->parent_id = parent_id;
|
||||
shape->edges = NULL;
|
||||
|
||||
@ -466,18 +466,18 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
|
||||
|
||||
switch (shape_type) {
|
||||
case SHAPE_IVAR:
|
||||
if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
|
||||
RUBY_ASSERT(shape->next_iv_index == shape->capacity);
|
||||
if (UNLIKELY(shape->next_field_index >= shape->capacity)) {
|
||||
RUBY_ASSERT(shape->next_field_index == shape->capacity);
|
||||
new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity, sizeof(VALUE));
|
||||
}
|
||||
RUBY_ASSERT(new_shape->capacity > shape->next_iv_index);
|
||||
new_shape->next_iv_index = shape->next_iv_index + 1;
|
||||
if (new_shape->next_iv_index > ANCESTOR_CACHE_THRESHOLD) {
|
||||
RUBY_ASSERT(new_shape->capacity > shape->next_field_index);
|
||||
new_shape->next_field_index = shape->next_field_index + 1;
|
||||
if (new_shape->next_field_index > ANCESTOR_CACHE_THRESHOLD) {
|
||||
redblack_cache_ancestors(new_shape);
|
||||
}
|
||||
break;
|
||||
case SHAPE_FROZEN:
|
||||
new_shape->next_iv_index = shape->next_iv_index;
|
||||
new_shape->next_field_index = shape->next_field_index;
|
||||
break;
|
||||
case SHAPE_OBJ_TOO_COMPLEX:
|
||||
case SHAPE_ROOT:
|
||||
@ -639,39 +639,39 @@ rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE
|
||||
return false;
|
||||
}
|
||||
|
||||
RUBY_ASSERT(new_shape->next_iv_index == shape->next_iv_index - 1);
|
||||
RUBY_ASSERT(new_shape->next_field_index == shape->next_field_index - 1);
|
||||
|
||||
VALUE *ivptr;
|
||||
VALUE *fields;
|
||||
switch(BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
ivptr = RCLASS_IVPTR(obj);
|
||||
fields = RCLASS_FIELDS(obj);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
ivptr = ROBJECT_IVPTR(obj);
|
||||
fields = ROBJECT_FIELDS(obj);
|
||||
break;
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_gen_ivtbl_get(obj, id, &ivtbl);
|
||||
ivptr = ivtbl->as.shape.ivptr;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
rb_gen_fields_tbl_get(obj, id, &fields_tbl);
|
||||
fields = fields_tbl->as.shape.fields;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*removed = ivptr[removed_shape->next_iv_index - 1];
|
||||
*removed = fields[removed_shape->next_field_index - 1];
|
||||
|
||||
memmove(&ivptr[removed_shape->next_iv_index - 1], &ivptr[removed_shape->next_iv_index],
|
||||
((new_shape->next_iv_index + 1) - removed_shape->next_iv_index) * sizeof(VALUE));
|
||||
memmove(&fields[removed_shape->next_field_index - 1], &fields[removed_shape->next_field_index],
|
||||
((new_shape->next_field_index + 1) - removed_shape->next_field_index) * sizeof(VALUE));
|
||||
|
||||
// Re-embed objects when instances become small enough
|
||||
// This is necessary because YJIT assumes that objects with the same shape
|
||||
// have the same embeddedness for efficiency (avoid extra checks)
|
||||
if (BUILTIN_TYPE(obj) == T_OBJECT &&
|
||||
!RB_FL_TEST_RAW(obj, ROBJECT_EMBED) &&
|
||||
rb_obj_embedded_size(new_shape->next_iv_index) <= rb_gc_obj_slot_size(obj)) {
|
||||
rb_obj_embedded_size(new_shape->next_field_index) <= rb_gc_obj_slot_size(obj)) {
|
||||
RB_FL_SET_RAW(obj, ROBJECT_EMBED);
|
||||
memcpy(ROBJECT_IVPTR(obj), ivptr, new_shape->next_iv_index * sizeof(VALUE));
|
||||
xfree(ivptr);
|
||||
memcpy(ROBJECT_FIELDS(obj), fields, new_shape->next_field_index * sizeof(VALUE));
|
||||
xfree(fields);
|
||||
}
|
||||
|
||||
rb_shape_set_shape(obj, new_shape);
|
||||
@ -743,8 +743,8 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
|
||||
// Check if we should update max_iv_count on the object's class
|
||||
if (BUILTIN_TYPE(obj) == T_OBJECT) {
|
||||
VALUE klass = rb_obj_class(obj);
|
||||
if (new_shape->next_iv_index > RCLASS_EXT(klass)->max_iv_count) {
|
||||
RCLASS_EXT(klass)->max_iv_count = new_shape->next_iv_index;
|
||||
if (new_shape->next_field_index > RCLASS_EXT(klass)->max_iv_count) {
|
||||
RCLASS_EXT(klass)->max_iv_count = new_shape->next_field_index;
|
||||
}
|
||||
|
||||
if (variation_created) {
|
||||
@ -799,12 +799,12 @@ rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value,
|
||||
// eventually using the index, as in case of a match it will be faster.
|
||||
// However if the shape doesn't have an index, we walk the entire tree.
|
||||
int depth = INT_MAX;
|
||||
if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
if (shape->ancestor_index && shape->next_field_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
depth = ANCESTOR_SEARCH_MAX_DEPTH;
|
||||
}
|
||||
|
||||
while (depth > 0 && shape->next_iv_index > index_hint) {
|
||||
while (shape_hint->next_iv_index > shape->next_iv_index) {
|
||||
while (depth > 0 && shape->next_field_index > index_hint) {
|
||||
while (shape_hint->next_field_index > shape->next_field_index) {
|
||||
shape_hint = rb_shape_get_parent(shape_hint);
|
||||
}
|
||||
|
||||
@ -816,7 +816,7 @@ rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value,
|
||||
}
|
||||
if (shape->edge_name == id) {
|
||||
// We found the matching id before a common ancestor
|
||||
*value = shape->next_iv_index - 1;
|
||||
*value = shape->next_field_index - 1;
|
||||
*shape_id_hint = rb_shape_id(shape);
|
||||
return true;
|
||||
}
|
||||
@ -844,8 +844,8 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
|
||||
|
||||
switch (shape_type) {
|
||||
case SHAPE_IVAR:
|
||||
RUBY_ASSERT(shape->next_iv_index > 0);
|
||||
*value = shape->next_iv_index - 1;
|
||||
RUBY_ASSERT(shape->next_field_index > 0);
|
||||
*value = shape->next_field_index - 1;
|
||||
return true;
|
||||
case SHAPE_ROOT:
|
||||
case SHAPE_T_OBJECT:
|
||||
@ -865,11 +865,11 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
|
||||
static bool
|
||||
shape_cache_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
|
||||
{
|
||||
if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
if (shape->ancestor_index && shape->next_field_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
redblack_node_t *node = redblack_find(shape->ancestor_index, id);
|
||||
if (node) {
|
||||
rb_shape_t *shape = redblack_value(node);
|
||||
*value = shape->next_iv_index - 1;
|
||||
*value = shape->next_field_index - 1;
|
||||
|
||||
#if RUBY_DEBUG
|
||||
attr_index_t shape_tree_index;
|
||||
@ -897,7 +897,7 @@ rb_shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
|
||||
|
||||
if (!shape_cache_get_iv_index(shape, id, value)) {
|
||||
// If it wasn't in the ancestor cache, then don't do a linear search
|
||||
if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
if (shape->ancestor_index && shape->next_field_index >= ANCESTOR_CACHE_THRESHOLD) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
@ -1074,7 +1074,7 @@ rb_shape_t_to_rb_cShape(rb_shape_t *shape)
|
||||
INT2NUM(rb_shape_id(shape)),
|
||||
INT2NUM(shape->parent_id),
|
||||
rb_shape_edge_name(shape),
|
||||
INT2NUM(shape->next_iv_index),
|
||||
INT2NUM(shape->next_field_index),
|
||||
INT2NUM(shape->heap_index),
|
||||
INT2NUM(shape->type),
|
||||
INT2NUM(shape->capacity));
|
||||
@ -1323,7 +1323,7 @@ Init_shape(void)
|
||||
"id",
|
||||
"parent_id",
|
||||
"edge_name",
|
||||
"next_iv_index",
|
||||
"next_field_index",
|
||||
"heap_index",
|
||||
"type",
|
||||
"capacity",
|
||||
|
24
shape.h
24
shape.h
@ -23,7 +23,7 @@ typedef uint16_t shape_id_t;
|
||||
|
||||
typedef uint32_t redblack_id_t;
|
||||
|
||||
#define MAX_IVARS (attr_index_t)(-1)
|
||||
#define SHAPE_MAX_FIELDS (attr_index_t)(-1)
|
||||
|
||||
# define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
|
||||
# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
|
||||
@ -44,7 +44,7 @@ typedef struct redblack_node redblack_node_t;
|
||||
struct rb_shape {
|
||||
struct rb_id_table *edges; // id_table from ID (ivar) to next shape
|
||||
ID edge_name; // ID (ivar) for transition from parent to rb_shape
|
||||
attr_index_t next_iv_index;
|
||||
attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id`
|
||||
attr_index_t capacity; // Total capacity of the object with this shape
|
||||
uint8_t type;
|
||||
uint8_t heap_index;
|
||||
@ -169,7 +169,7 @@ rb_shape_t *rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id);
|
||||
rb_shape_t *rb_shape_rebuild_shape(rb_shape_t *initial_shape, rb_shape_t *dest_shape);
|
||||
|
||||
static inline uint32_t
|
||||
ROBJECT_IV_CAPACITY(VALUE obj)
|
||||
ROBJECT_FIELDS_CAPACITY(VALUE obj)
|
||||
{
|
||||
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
|
||||
// Asking for capacity doesn't make sense when the object is using
|
||||
@ -179,40 +179,40 @@ ROBJECT_IV_CAPACITY(VALUE obj)
|
||||
}
|
||||
|
||||
static inline st_table *
|
||||
ROBJECT_IV_HASH(VALUE obj)
|
||||
ROBJECT_FIELDS_HASH(VALUE obj)
|
||||
{
|
||||
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
return (st_table *)ROBJECT(obj)->as.heap.ivptr;
|
||||
return (st_table *)ROBJECT(obj)->as.heap.fields;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
|
||||
ROBJECT_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
|
||||
{
|
||||
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
|
||||
ROBJECT(obj)->as.heap.fields = (VALUE *)tbl;
|
||||
}
|
||||
|
||||
size_t rb_id_table_size(const struct rb_id_table *tbl);
|
||||
|
||||
static inline uint32_t
|
||||
ROBJECT_IV_COUNT(VALUE obj)
|
||||
ROBJECT_FIELDS_COUNT(VALUE obj)
|
||||
{
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
|
||||
return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
|
||||
}
|
||||
else {
|
||||
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
|
||||
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_field_index;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
RBASIC_IV_COUNT(VALUE obj)
|
||||
RBASIC_FIELDS_COUNT(VALUE obj)
|
||||
{
|
||||
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
|
||||
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_field_index;
|
||||
}
|
||||
|
||||
rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
|
||||
|
@ -888,7 +888,7 @@ describe "CApiObject" do
|
||||
end
|
||||
end
|
||||
|
||||
# The `generic_iv_tbl` table and `*_generic_ivar` functions are for mutable
|
||||
# The `generic_fields_tbl` table and `*_generic_ivar` functions are for mutable
|
||||
# objects which do not store ivars directly in MRI such as RString, because
|
||||
# there is no member iv_index_tbl (ivar table) such as in RObject and RClass.
|
||||
|
||||
|
4
st.c
4
st.c
@ -748,7 +748,7 @@ rebuild_table(st_table *tab)
|
||||
else {
|
||||
st_table *new_tab;
|
||||
/* This allocation could trigger GC and compaction. If tab is the
|
||||
* gen_iv_tbl, then tab could have changed in size due to objects being
|
||||
* gen_fields_tbl, then tab could have changed in size due to objects being
|
||||
* freed and/or moved. Do not store attributes of tab before this line. */
|
||||
new_tab = st_init_table_with_size(tab->type,
|
||||
2 * tab->num_entries - 1);
|
||||
@ -2534,7 +2534,7 @@ set_rebuild_table(set_table *tab)
|
||||
else {
|
||||
set_table *new_tab;
|
||||
/* This allocation could trigger GC and compaction. If tab is the
|
||||
* gen_iv_tbl, then tab could have changed in size due to objects being
|
||||
* gen_fields_tbl, then tab could have changed in size due to objects being
|
||||
* freed and/or moved. Do not store attributes of tab before this line. */
|
||||
new_tab = set_init_table_with_size(NULL, tab->type,
|
||||
2 * tab->num_entries - 1);
|
||||
|
@ -852,13 +852,13 @@ class TestShapes < Test::Unit::TestCase
|
||||
def test_iv_index
|
||||
example = RemoveAndAdd.new
|
||||
initial_shape = RubyVM::Shape.of(example)
|
||||
assert_equal 0, initial_shape.next_iv_index
|
||||
assert_equal 0, initial_shape.next_field_index
|
||||
|
||||
example.add_foo # makes a transition
|
||||
add_foo_shape = RubyVM::Shape.of(example)
|
||||
assert_equal([:@foo], example.instance_variables)
|
||||
assert_equal(initial_shape.id, add_foo_shape.parent.id)
|
||||
assert_equal(1, add_foo_shape.next_iv_index)
|
||||
assert_equal(1, add_foo_shape.next_field_index)
|
||||
|
||||
example.remove_foo # makes a transition
|
||||
remove_foo_shape = RubyVM::Shape.of(example)
|
||||
@ -869,7 +869,7 @@ class TestShapes < Test::Unit::TestCase
|
||||
bar_shape = RubyVM::Shape.of(example)
|
||||
assert_equal([:@bar], example.instance_variables)
|
||||
assert_equal(initial_shape.id, bar_shape.parent_id)
|
||||
assert_equal(1, bar_shape.next_iv_index)
|
||||
assert_equal(1, bar_shape.next_field_index)
|
||||
end
|
||||
|
||||
def test_remove_then_add_again
|
||||
|
344
variable.c
344
variable.c
@ -61,13 +61,13 @@ static VALUE autoload_mutex;
|
||||
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
|
||||
static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
|
||||
static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility);
|
||||
static st_table *generic_iv_tbl_;
|
||||
static st_table *generic_fields_tbl_;
|
||||
|
||||
void
|
||||
Init_var_tables(void)
|
||||
{
|
||||
rb_global_tbl = rb_id_table_create(0);
|
||||
generic_iv_tbl_ = st_init_numtable();
|
||||
generic_fields_tbl_ = st_init_numtable();
|
||||
autoload = rb_intern_const("__autoload__");
|
||||
|
||||
autoload_mutex = rb_mutex_new();
|
||||
@ -567,9 +567,9 @@ rb_free_rb_global_tbl(void)
|
||||
}
|
||||
|
||||
void
|
||||
rb_free_generic_iv_tbl_(void)
|
||||
rb_free_generic_fields_tbl_(void)
|
||||
{
|
||||
st_free_table(generic_iv_tbl_);
|
||||
st_free_table(generic_fields_tbl_);
|
||||
}
|
||||
|
||||
static struct rb_global_entry*
|
||||
@ -1125,7 +1125,7 @@ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
|
||||
}
|
||||
|
||||
static inline struct st_table *
|
||||
generic_ivtbl(VALUE obj, ID id, bool force_check_ractor)
|
||||
generic_fields_tbl(VALUE obj, ID id, bool force_check_ractor)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
|
||||
@ -1136,23 +1136,23 @@ generic_ivtbl(VALUE obj, ID id, bool force_check_ractor)
|
||||
|
||||
rb_raise(rb_eRactorIsolationError, "can not access instance variables of shareable objects from non-main Ractors");
|
||||
}
|
||||
return generic_iv_tbl_;
|
||||
return generic_fields_tbl_;
|
||||
}
|
||||
|
||||
static inline struct st_table *
|
||||
generic_ivtbl_no_ractor_check(VALUE obj)
|
||||
generic_fields_tbl_no_ractor_check(VALUE obj)
|
||||
{
|
||||
return generic_ivtbl(obj, 0, false);
|
||||
return generic_fields_tbl(obj, 0, false);
|
||||
}
|
||||
|
||||
struct st_table *
|
||||
rb_generic_ivtbl_get(void)
|
||||
rb_generic_fields_tbl_get(void)
|
||||
{
|
||||
return generic_iv_tbl_;
|
||||
return generic_fields_tbl_;
|
||||
}
|
||||
|
||||
int
|
||||
rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl)
|
||||
rb_gen_fields_tbl_get(VALUE obj, ID id, struct gen_fields_tbl **fields_tbl)
|
||||
{
|
||||
RUBY_ASSERT(!RB_TYPE_P(obj, T_ICLASS));
|
||||
|
||||
@ -1161,8 +1161,8 @@ rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl)
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
if (st_lookup(generic_ivtbl(obj, id, false), (st_data_t)obj, &data)) {
|
||||
*ivtbl = (struct gen_ivtbl *)data;
|
||||
if (st_lookup(generic_fields_tbl(obj, id, false), (st_data_t)obj, &data)) {
|
||||
*fields_tbl = (struct gen_fields_tbl *)data;
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
@ -1172,45 +1172,45 @@ rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl)
|
||||
}
|
||||
|
||||
int
|
||||
rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl)
|
||||
rb_ivar_generic_fields_tbl_lookup(VALUE obj, struct gen_fields_tbl **fields_tbl)
|
||||
{
|
||||
return rb_gen_ivtbl_get(obj, 0, ivtbl);
|
||||
return rb_gen_fields_tbl_get(obj, 0, fields_tbl);
|
||||
}
|
||||
|
||||
static size_t
|
||||
gen_ivtbl_bytes(size_t n)
|
||||
gen_fields_tbl_bytes(size_t n)
|
||||
{
|
||||
return offsetof(struct gen_ivtbl, as.shape.ivptr) + n * sizeof(VALUE);
|
||||
return offsetof(struct gen_fields_tbl, as.shape.fields) + n * sizeof(VALUE);
|
||||
}
|
||||
|
||||
static struct gen_ivtbl *
|
||||
gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n)
|
||||
static struct gen_fields_tbl *
|
||||
gen_fields_tbl_resize(struct gen_fields_tbl *old, uint32_t n)
|
||||
{
|
||||
RUBY_ASSERT(n > 0);
|
||||
|
||||
uint32_t len = old ? old->as.shape.numiv : 0;
|
||||
struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
|
||||
uint32_t len = old ? old->as.shape.fields_count : 0;
|
||||
struct gen_fields_tbl *fields_tbl = xrealloc(old, gen_fields_tbl_bytes(n));
|
||||
|
||||
ivtbl->as.shape.numiv = n;
|
||||
fields_tbl->as.shape.fields_count = n;
|
||||
for (; len < n; len++) {
|
||||
ivtbl->as.shape.ivptr[len] = Qundef;
|
||||
fields_tbl->as.shape.fields[len] = Qundef;
|
||||
}
|
||||
|
||||
return ivtbl;
|
||||
return fields_tbl;
|
||||
}
|
||||
|
||||
void
|
||||
rb_mark_generic_ivar(VALUE obj)
|
||||
{
|
||||
st_data_t data;
|
||||
if (st_lookup(generic_ivtbl_no_ractor_check(obj), (st_data_t)obj, &data)) {
|
||||
struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)data;
|
||||
if (st_lookup(generic_fields_tbl_no_ractor_check(obj), (st_data_t)obj, &data)) {
|
||||
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)data;
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
rb_mark_tbl_no_pin(ivtbl->as.complex.table);
|
||||
rb_mark_tbl_no_pin(fields_tbl->as.complex.table);
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
rb_gc_mark_movable(ivtbl->as.shape.ivptr[i]);
|
||||
for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
|
||||
rb_gc_mark_movable(fields_tbl->as.shape.fields[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1223,28 +1223,28 @@ rb_free_generic_ivar(VALUE obj)
|
||||
|
||||
bool too_complex = rb_shape_obj_too_complex(obj);
|
||||
|
||||
if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, &value)) {
|
||||
struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
|
||||
if (st_delete(generic_fields_tbl_no_ractor_check(obj), &key, &value)) {
|
||||
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value;
|
||||
|
||||
if (UNLIKELY(too_complex)) {
|
||||
st_free_table(ivtbl->as.complex.table);
|
||||
st_free_table(fields_tbl->as.complex.table);
|
||||
}
|
||||
|
||||
xfree(ivtbl);
|
||||
xfree(fields_tbl);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
rb_generic_ivar_memsize(VALUE obj)
|
||||
{
|
||||
struct gen_ivtbl *ivtbl;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
|
||||
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
return sizeof(struct gen_ivtbl) + st_memsize(ivtbl->as.complex.table);
|
||||
return sizeof(struct gen_fields_tbl) + st_memsize(fields_tbl->as.complex.table);
|
||||
}
|
||||
else {
|
||||
return gen_ivtbl_bytes(ivtbl->as.shape.numiv);
|
||||
return gen_fields_tbl_bytes(fields_tbl->as.shape.fields_count);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -1254,15 +1254,15 @@ rb_generic_ivar_memsize(VALUE obj)
|
||||
shape_id_t
|
||||
rb_generic_shape_id(VALUE obj)
|
||||
{
|
||||
struct gen_ivtbl *ivtbl = 0;
|
||||
struct gen_fields_tbl *fields_tbl = 0;
|
||||
shape_id_t shape_id = 0;
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
st_table* global_iv_table = generic_ivtbl(obj, 0, false);
|
||||
st_table* global_iv_table = generic_fields_tbl(obj, 0, false);
|
||||
|
||||
if (global_iv_table && st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) {
|
||||
shape_id = ivtbl->shape_id;
|
||||
if (global_iv_table && st_lookup(global_iv_table, obj, (st_data_t *)&fields_tbl)) {
|
||||
shape_id = fields_tbl->shape_id;
|
||||
}
|
||||
else if (OBJ_FROZEN(obj)) {
|
||||
shape_id = SPECIAL_CONST_SHAPE_ID;
|
||||
@ -1275,17 +1275,17 @@ rb_generic_shape_id(VALUE obj)
|
||||
#endif
|
||||
|
||||
static size_t
|
||||
gen_ivtbl_count(VALUE obj, const struct gen_ivtbl *ivtbl)
|
||||
gen_fields_tbl_count(VALUE obj, const struct gen_fields_tbl *fields_tbl)
|
||||
{
|
||||
uint32_t i;
|
||||
size_t n = 0;
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
n = st_table_size(ivtbl->as.complex.table);
|
||||
n = st_table_size(fields_tbl->as.complex.table);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < ivtbl->as.shape.numiv; i++) {
|
||||
if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
|
||||
for (i = 0; i < fields_tbl->as.shape.fields_count; i++) {
|
||||
if (!UNDEF_P(fields_tbl->as.shape.fields[i])) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@ -1321,7 +1321,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
|
||||
#endif
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
st_table * iv_table = RCLASS_IV_HASH(obj);
|
||||
st_table * iv_table = RCLASS_FIELDS_HASH(obj);
|
||||
if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
|
||||
found = true;
|
||||
}
|
||||
@ -1335,7 +1335,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
|
||||
found = rb_shape_get_iv_index(shape, id, &index);
|
||||
|
||||
if (found) {
|
||||
ivar_list = RCLASS_IVPTR(obj);
|
||||
ivar_list = RCLASS_FIELDS(obj);
|
||||
RUBY_ASSERT(ivar_list);
|
||||
|
||||
val = ivar_list[index];
|
||||
@ -1362,7 +1362,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
|
||||
shape_id = ROBJECT_SHAPE_ID(obj);
|
||||
#endif
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
st_table * iv_table = ROBJECT_IV_HASH(obj);
|
||||
st_table * iv_table = ROBJECT_FIELDS_HASH(obj);
|
||||
VALUE val;
|
||||
if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
|
||||
return val;
|
||||
@ -1373,17 +1373,17 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
|
||||
}
|
||||
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
ivar_list = ROBJECT_IVPTR(obj);
|
||||
ivar_list = ROBJECT_FIELDS(obj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (FL_TEST_RAW(obj, FL_EXIVAR)) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_gen_ivtbl_get(obj, id, &ivtbl);
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
rb_gen_fields_tbl_get(obj, id, &fields_tbl);
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
VALUE val;
|
||||
if (rb_st_lookup(ivtbl->as.complex.table, (st_data_t)id, (st_data_t *)&val)) {
|
||||
if (rb_st_lookup(fields_tbl->as.complex.table, (st_data_t)id, (st_data_t *)&val)) {
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
@ -1392,9 +1392,9 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
|
||||
}
|
||||
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
shape_id = ivtbl->shape_id;
|
||||
shape_id = fields_tbl->shape_id;
|
||||
#endif
|
||||
ivar_list = ivtbl->as.shape.ivptr;
|
||||
ivar_list = fields_tbl->as.shape.fields;
|
||||
}
|
||||
else {
|
||||
return undef;
|
||||
@ -1446,17 +1446,17 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = RCLASS_IV_HASH(obj);
|
||||
table = RCLASS_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
table = ROBJECT_IV_HASH(obj);
|
||||
table = ROBJECT_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
table = ivtbl->as.complex.table;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
table = fields_tbl->as.complex.table;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1483,57 +1483,57 @@ rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
|
||||
{
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
|
||||
VALUE *old_ivptr = NULL;
|
||||
VALUE *old_fields = NULL;
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_OBJECT:
|
||||
if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
|
||||
old_ivptr = ROBJECT_IVPTR(obj);
|
||||
old_fields = ROBJECT_FIELDS(obj);
|
||||
}
|
||||
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||
ROBJECT_SET_IV_HASH(obj, table);
|
||||
ROBJECT_SET_FIELDS_HASH(obj, table);
|
||||
break;
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
old_ivptr = RCLASS_IVPTR(obj);
|
||||
old_fields = RCLASS_FIELDS(obj);
|
||||
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||
RCLASS_SET_IV_HASH(obj, table);
|
||||
RCLASS_SET_FIELDS_HASH(obj, table);
|
||||
break;
|
||||
default:
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj);
|
||||
struct st_table *gen_ivs = generic_fields_tbl_no_ractor_check(obj);
|
||||
|
||||
struct gen_ivtbl *old_ivtbl = NULL;
|
||||
st_lookup(gen_ivs, (st_data_t)obj, (st_data_t *)&old_ivtbl);
|
||||
struct gen_fields_tbl *old_fields_tbl = NULL;
|
||||
st_lookup(gen_ivs, (st_data_t)obj, (st_data_t *)&old_fields_tbl);
|
||||
|
||||
if (old_ivtbl) {
|
||||
/* We need to modify old_ivtbl to have the too complex shape
|
||||
if (old_fields_tbl) {
|
||||
/* We need to modify old_fields_tbl to have the too complex shape
|
||||
* and hold the table because the xmalloc could trigger a GC
|
||||
* compaction. We want the table to be updated rather than
|
||||
* the original ivptr. */
|
||||
* the original fields. */
|
||||
#if SHAPE_IN_BASIC_FLAGS
|
||||
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||
#else
|
||||
old_ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
old_fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
#endif
|
||||
old_ivtbl->as.complex.table = table;
|
||||
old_ivptr = (VALUE *)old_ivtbl;
|
||||
old_fields_tbl->as.complex.table = table;
|
||||
old_fields = (VALUE *)old_fields_tbl;
|
||||
}
|
||||
|
||||
struct gen_ivtbl *ivtbl = xmalloc(sizeof(struct gen_ivtbl));
|
||||
ivtbl->as.complex.table = table;
|
||||
st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl);
|
||||
struct gen_fields_tbl *fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
|
||||
fields_tbl->as.complex.table = table;
|
||||
st_insert(gen_ivs, (st_data_t)obj, (st_data_t)fields_tbl);
|
||||
#if SHAPE_IN_BASIC_FLAGS
|
||||
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
|
||||
#else
|
||||
ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
#endif
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
}
|
||||
|
||||
xfree(old_ivptr);
|
||||
xfree(old_fields);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1557,8 +1557,8 @@ struct general_ivar_set_result {
|
||||
|
||||
static struct general_ivar_set_result
|
||||
general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
|
||||
VALUE *(*shape_ivptr_func)(VALUE, void *),
|
||||
void (*shape_resize_ivptr_func)(VALUE, attr_index_t, attr_index_t, void *),
|
||||
VALUE *(*shape_fields_func)(VALUE, void *),
|
||||
void (*shape_resize_fields_func)(VALUE, attr_index_t, attr_index_t, void *),
|
||||
void (*set_shape_func)(VALUE, rb_shape_t *, void *),
|
||||
void (*transition_too_complex_func)(VALUE, void *),
|
||||
st_table *(*too_complex_table_func)(VALUE, void *))
|
||||
@ -1578,8 +1578,8 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
|
||||
if (!rb_shape_get_iv_index(current_shape, id, &index)) {
|
||||
result.existing = false;
|
||||
|
||||
index = current_shape->next_iv_index;
|
||||
if (index >= MAX_IVARS) {
|
||||
index = current_shape->next_field_index;
|
||||
if (index >= SHAPE_MAX_FIELDS) {
|
||||
rb_raise(rb_eArgError, "too many instance variables");
|
||||
}
|
||||
|
||||
@ -1590,15 +1590,15 @@ general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
|
||||
}
|
||||
else if (UNLIKELY(next_shape->capacity != current_shape->capacity)) {
|
||||
RUBY_ASSERT(next_shape->capacity > current_shape->capacity);
|
||||
shape_resize_ivptr_func(obj, current_shape->capacity, next_shape->capacity, data);
|
||||
shape_resize_fields_func(obj, current_shape->capacity, next_shape->capacity, data);
|
||||
}
|
||||
|
||||
RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
|
||||
RUBY_ASSERT(index == (next_shape->next_iv_index - 1));
|
||||
RUBY_ASSERT(index == (next_shape->next_field_index - 1));
|
||||
set_shape_func(obj, next_shape, data);
|
||||
}
|
||||
|
||||
VALUE *table = shape_ivptr_func(obj, data);
|
||||
VALUE *table = shape_fields_func(obj, data);
|
||||
RB_OBJ_WRITE(obj, &table[index], val);
|
||||
|
||||
result.index = index;
|
||||
@ -1616,10 +1616,10 @@ too_complex:
|
||||
return result;
|
||||
}
|
||||
|
||||
struct gen_ivar_lookup_ensure_size {
|
||||
struct gen_fields_lookup_ensure_size {
|
||||
VALUE obj;
|
||||
ID id;
|
||||
struct gen_ivtbl *ivtbl;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
rb_shape_t *shape;
|
||||
bool resize;
|
||||
};
|
||||
@ -1629,8 +1629,8 @@ generic_ivar_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int exi
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
|
||||
struct gen_ivar_lookup_ensure_size *ivar_lookup = (struct gen_ivar_lookup_ensure_size *)u;
|
||||
struct gen_ivtbl *ivtbl = existing ? (struct gen_ivtbl *)*v : NULL;
|
||||
struct gen_fields_lookup_ensure_size *ivar_lookup = (struct gen_fields_lookup_ensure_size *)u;
|
||||
struct gen_fields_tbl *fields_tbl = existing ? (struct gen_fields_tbl *)*v : NULL;
|
||||
|
||||
if (!existing || ivar_lookup->resize) {
|
||||
if (existing) {
|
||||
@ -1641,18 +1641,18 @@ generic_ivar_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int exi
|
||||
FL_SET_RAW((VALUE)*k, FL_EXIVAR);
|
||||
}
|
||||
|
||||
ivtbl = gen_ivtbl_resize(ivtbl, ivar_lookup->shape->capacity);
|
||||
*v = (st_data_t)ivtbl;
|
||||
fields_tbl = gen_fields_tbl_resize(fields_tbl, ivar_lookup->shape->capacity);
|
||||
*v = (st_data_t)fields_tbl;
|
||||
}
|
||||
|
||||
RUBY_ASSERT(FL_TEST((VALUE)*k, FL_EXIVAR));
|
||||
|
||||
ivar_lookup->ivtbl = ivtbl;
|
||||
ivar_lookup->fields_tbl = fields_tbl;
|
||||
if (ivar_lookup->shape) {
|
||||
#if SHAPE_IN_BASIC_FLAGS
|
||||
rb_shape_set_shape(ivar_lookup->obj, ivar_lookup->shape);
|
||||
#else
|
||||
ivtbl->shape_id = rb_shape_id(ivar_lookup->shape);
|
||||
fields_tbl->shape_id = rb_shape_id(ivar_lookup->shape);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1660,27 +1660,27 @@ generic_ivar_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int exi
|
||||
}
|
||||
|
||||
static VALUE *
|
||||
generic_ivar_set_shape_ivptr(VALUE obj, void *data)
|
||||
generic_ivar_set_shape_fields(VALUE obj, void *data)
|
||||
{
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
|
||||
struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
|
||||
struct gen_fields_lookup_ensure_size *ivar_lookup = data;
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
st_update(generic_ivtbl(obj, ivar_lookup->id, false), (st_data_t)obj, generic_ivar_lookup_ensure_size, (st_data_t)ivar_lookup);
|
||||
st_update(generic_fields_tbl(obj, ivar_lookup->id, false), (st_data_t)obj, generic_ivar_lookup_ensure_size, (st_data_t)ivar_lookup);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
FL_SET_RAW(obj, FL_EXIVAR);
|
||||
|
||||
return ivar_lookup->ivtbl->as.shape.ivptr;
|
||||
return ivar_lookup->fields_tbl->as.shape.fields;
|
||||
}
|
||||
|
||||
static void
|
||||
generic_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *data)
|
||||
generic_ivar_set_shape_resize_fields(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *data)
|
||||
{
|
||||
struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
|
||||
struct gen_fields_lookup_ensure_size *ivar_lookup = data;
|
||||
|
||||
ivar_lookup->resize = true;
|
||||
}
|
||||
@ -1688,7 +1688,7 @@ generic_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t _old_capa, attr_inde
|
||||
static void
|
||||
generic_ivar_set_set_shape(VALUE obj, rb_shape_t *shape, void *data)
|
||||
{
|
||||
struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
|
||||
struct gen_fields_lookup_ensure_size *ivar_lookup = data;
|
||||
|
||||
ivar_lookup->shape = shape;
|
||||
}
|
||||
@ -1703,19 +1703,19 @@ generic_ivar_set_transition_too_complex(VALUE obj, void *_data)
|
||||
static st_table *
|
||||
generic_ivar_set_too_complex_table(VALUE obj, void *data)
|
||||
{
|
||||
struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
|
||||
struct gen_fields_lookup_ensure_size *ivar_lookup = data;
|
||||
|
||||
struct gen_ivtbl *ivtbl;
|
||||
if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
ivtbl = xmalloc(sizeof(struct gen_ivtbl));
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
if (!rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
#endif
|
||||
ivtbl->as.complex.table = st_init_numtable_with_size(1);
|
||||
fields_tbl->as.complex.table = st_init_numtable_with_size(1);
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
st_insert(generic_ivtbl(obj, ivar_lookup->id, false), (st_data_t)obj, (st_data_t)ivtbl);
|
||||
st_insert(generic_fields_tbl(obj, ivar_lookup->id, false), (st_data_t)obj, (st_data_t)fields_tbl);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
@ -1724,13 +1724,13 @@ generic_ivar_set_too_complex_table(VALUE obj, void *data)
|
||||
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
|
||||
return ivtbl->as.complex.table;
|
||||
return fields_tbl->as.complex.table;
|
||||
}
|
||||
|
||||
static void
|
||||
generic_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
{
|
||||
struct gen_ivar_lookup_ensure_size ivar_lookup = {
|
||||
struct gen_fields_lookup_ensure_size ivar_lookup = {
|
||||
.obj = obj,
|
||||
.id = id,
|
||||
.resize = false,
|
||||
@ -1738,8 +1738,8 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
};
|
||||
|
||||
general_ivar_set(obj, id, val, &ivar_lookup,
|
||||
generic_ivar_set_shape_ivptr,
|
||||
generic_ivar_set_shape_resize_ivptr,
|
||||
generic_ivar_set_shape_fields,
|
||||
generic_ivar_set_shape_resize_fields,
|
||||
generic_ivar_set_set_shape,
|
||||
generic_ivar_set_transition_too_complex,
|
||||
generic_ivar_set_too_complex_table);
|
||||
@ -1751,14 +1751,14 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capaci
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
|
||||
if (RBASIC(obj)->flags & ROBJECT_EMBED) {
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
VALUE *ptr = ROBJECT_FIELDS(obj);
|
||||
VALUE *newptr = ALLOC_N(VALUE, new_capacity);
|
||||
MEMCPY(newptr, ptr, VALUE, current_capacity);
|
||||
RB_FL_UNSET_RAW(obj, ROBJECT_EMBED);
|
||||
ROBJECT(obj)->as.heap.ivptr = newptr;
|
||||
ROBJECT(obj)->as.heap.fields = newptr;
|
||||
}
|
||||
else {
|
||||
REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, new_capacity);
|
||||
REALLOC_N(ROBJECT(obj)->as.heap.fields, VALUE, new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1778,15 +1778,15 @@ rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table)
|
||||
}
|
||||
|
||||
static VALUE *
|
||||
obj_ivar_set_shape_ivptr(VALUE obj, void *_data)
|
||||
obj_ivar_set_shape_fields(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
|
||||
return ROBJECT_IVPTR(obj);
|
||||
return ROBJECT_FIELDS(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
obj_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t old_capa, attr_index_t new_capa, void *_data)
|
||||
obj_ivar_set_shape_resize_fields(VALUE obj, attr_index_t old_capa, attr_index_t new_capa, void *_data)
|
||||
{
|
||||
rb_ensure_iv_list_size(obj, old_capa, new_capa);
|
||||
}
|
||||
@ -1808,15 +1808,15 @@ obj_ivar_set_too_complex_table(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
|
||||
return ROBJECT_IV_HASH(obj);
|
||||
return ROBJECT_FIELDS_HASH(obj);
|
||||
}
|
||||
|
||||
attr_index_t
|
||||
rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
{
|
||||
return general_ivar_set(obj, id, val, NULL,
|
||||
obj_ivar_set_shape_ivptr,
|
||||
obj_ivar_set_shape_resize_ivptr,
|
||||
obj_ivar_set_shape_fields,
|
||||
obj_ivar_set_shape_resize_fields,
|
||||
obj_ivar_set_set_shape,
|
||||
obj_ivar_set_transition_too_complex,
|
||||
obj_ivar_set_too_complex_table).index;
|
||||
@ -1854,13 +1854,13 @@ rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id)
|
||||
break;
|
||||
default:
|
||||
if (shape_id != SPECIAL_CONST_SHAPE_ID) {
|
||||
struct gen_ivtbl *ivtbl = 0;
|
||||
struct gen_fields_tbl *fields_tbl = 0;
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
st_table* global_iv_table = generic_ivtbl(obj, 0, false);
|
||||
st_table* global_iv_table = generic_fields_tbl(obj, 0, false);
|
||||
|
||||
if (st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) {
|
||||
ivtbl->shape_id = shape_id;
|
||||
if (st_lookup(global_iv_table, obj, (st_data_t *)&fields_tbl)) {
|
||||
fields_tbl->shape_id = shape_id;
|
||||
}
|
||||
else {
|
||||
rb_bug("Expected shape_id entry in global iv table");
|
||||
@ -1949,17 +1949,17 @@ rb_ivar_defined(VALUE obj, ID id)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = (st_table *)RCLASS_IVPTR(obj);
|
||||
table = (st_table *)RCLASS_FIELDS(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
table = ROBJECT_IV_HASH(obj);
|
||||
table = ROBJECT_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
table = ivtbl->as.complex.table;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
table = fields_tbl->as.complex.table;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1980,7 +1980,7 @@ typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg);
|
||||
|
||||
struct iv_itr_data {
|
||||
VALUE obj;
|
||||
struct gen_ivtbl * ivtbl;
|
||||
struct gen_fields_tbl * fields_tbl;
|
||||
st_data_t arg;
|
||||
rb_ivar_foreach_callback_func *func;
|
||||
};
|
||||
@ -2003,17 +2003,17 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
|
||||
switch (BUILTIN_TYPE(itr_data->obj)) {
|
||||
case T_OBJECT:
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(itr_data->obj));
|
||||
iv_list = ROBJECT_IVPTR(itr_data->obj);
|
||||
iv_list = ROBJECT_FIELDS(itr_data->obj);
|
||||
break;
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
iv_list = RCLASS_IVPTR(itr_data->obj);
|
||||
iv_list = RCLASS_FIELDS(itr_data->obj);
|
||||
break;
|
||||
default:
|
||||
iv_list = itr_data->ivtbl->as.shape.ivptr;
|
||||
iv_list = itr_data->fields_tbl->as.shape.fields;
|
||||
break;
|
||||
}
|
||||
VALUE val = iv_list[shape->next_iv_index - 1];
|
||||
VALUE val = iv_list[shape->next_field_index - 1];
|
||||
if (!UNDEF_P(val)) {
|
||||
switch (callback(shape->edge_name, val, itr_data->arg)) {
|
||||
case ST_CHECK:
|
||||
@ -2051,7 +2051,7 @@ obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
itr_data.arg = arg;
|
||||
itr_data.func = func;
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
rb_st_foreach(ROBJECT_IV_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
|
||||
rb_st_foreach(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
|
||||
}
|
||||
else {
|
||||
iterate_over_shapes_with_callback(shape, func, &itr_data);
|
||||
@ -2059,19 +2059,19 @@ obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
}
|
||||
|
||||
static void
|
||||
gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
gen_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
{
|
||||
rb_shape_t *shape = rb_shape_get_shape(obj);
|
||||
struct gen_ivtbl *ivtbl;
|
||||
if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) return;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
if (!rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) return;
|
||||
|
||||
struct iv_itr_data itr_data;
|
||||
itr_data.obj = obj;
|
||||
itr_data.ivtbl = ivtbl;
|
||||
itr_data.fields_tbl = fields_tbl;
|
||||
itr_data.arg = arg;
|
||||
itr_data.func = func;
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
rb_st_foreach(ivtbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
|
||||
rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
|
||||
}
|
||||
else {
|
||||
iterate_over_shapes_with_callback(shape, func, &itr_data);
|
||||
@ -2089,7 +2089,7 @@ class_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
itr_data.arg = arg;
|
||||
itr_data.func = func;
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
rb_st_foreach(RCLASS_IV_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
|
||||
rb_st_foreach(RCLASS_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
|
||||
}
|
||||
else {
|
||||
iterate_over_shapes_with_callback(shape, func, &itr_data);
|
||||
@ -2099,8 +2099,8 @@ class_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
void
|
||||
rb_copy_generic_ivar(VALUE clone, VALUE obj)
|
||||
{
|
||||
struct gen_ivtbl *obj_ivtbl;
|
||||
struct gen_ivtbl *new_ivtbl;
|
||||
struct gen_fields_tbl *obj_fields_tbl;
|
||||
struct gen_fields_tbl *new_fields_tbl;
|
||||
|
||||
rb_check_frozen(clone);
|
||||
|
||||
@ -2108,35 +2108,35 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (rb_gen_ivtbl_get(obj, 0, &obj_ivtbl)) {
|
||||
if (gen_ivtbl_count(obj, obj_ivtbl) == 0)
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &obj_fields_tbl)) {
|
||||
if (gen_fields_tbl_count(obj, obj_fields_tbl) == 0)
|
||||
goto clear;
|
||||
|
||||
FL_SET(clone, FL_EXIVAR);
|
||||
|
||||
if (rb_shape_obj_too_complex(obj)) {
|
||||
new_ivtbl = xmalloc(sizeof(struct gen_ivtbl));
|
||||
new_fields_tbl = xmalloc(sizeof(struct gen_fields_tbl));
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
new_ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
new_fields_tbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
|
||||
#endif
|
||||
new_ivtbl->as.complex.table = st_copy(obj_ivtbl->as.complex.table);
|
||||
new_fields_tbl->as.complex.table = st_copy(obj_fields_tbl->as.complex.table);
|
||||
}
|
||||
else {
|
||||
new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->as.shape.numiv);
|
||||
new_fields_tbl = gen_fields_tbl_resize(0, obj_fields_tbl->as.shape.fields_count);
|
||||
|
||||
for (uint32_t i=0; i<obj_ivtbl->as.shape.numiv; i++) {
|
||||
RB_OBJ_WRITE(clone, &new_ivtbl->as.shape.ivptr[i], obj_ivtbl->as.shape.ivptr[i]);
|
||||
for (uint32_t i=0; i<obj_fields_tbl->as.shape.fields_count; i++) {
|
||||
RB_OBJ_WRITE(clone, &new_fields_tbl->as.shape.fields[i], obj_fields_tbl->as.shape.fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* c.ivtbl may change in gen_ivar_copy due to realloc,
|
||||
* c.fields_tbl may change in gen_fields_copy due to realloc,
|
||||
* no need to free
|
||||
*/
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
generic_ivtbl_no_ractor_check(clone);
|
||||
st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)new_ivtbl);
|
||||
generic_fields_tbl_no_ractor_check(clone);
|
||||
st_insert(generic_fields_tbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)new_fields_tbl);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
@ -2164,11 +2164,11 @@ rb_replace_generic_ivar(VALUE clone, VALUE obj)
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
st_data_t ivtbl, obj_data = (st_data_t)obj;
|
||||
if (st_delete(generic_iv_tbl_, &obj_data, &ivtbl)) {
|
||||
st_data_t fields_tbl, obj_data = (st_data_t)obj;
|
||||
if (st_delete(generic_fields_tbl_, &obj_data, &fields_tbl)) {
|
||||
FL_UNSET_RAW(obj, FL_EXIVAR);
|
||||
|
||||
st_insert(generic_iv_tbl_, (st_data_t)clone, ivtbl);
|
||||
st_insert(generic_fields_tbl_, (st_data_t)clone, fields_tbl);
|
||||
FL_SET_RAW(clone, FL_EXIVAR);
|
||||
}
|
||||
else {
|
||||
@ -2197,7 +2197,7 @@ rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||
break;
|
||||
default:
|
||||
if (FL_TEST(obj, FL_EXIVAR)) {
|
||||
gen_ivar_each(obj, func, arg);
|
||||
gen_fields_each(obj, func, arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2210,16 +2210,16 @@ rb_ivar_count(VALUE obj)
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_OBJECT:
|
||||
return ROBJECT_IV_COUNT(obj);
|
||||
return ROBJECT_FIELDS_COUNT(obj);
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
return RCLASS_IV_COUNT(obj);
|
||||
return RCLASS_FIELDS_COUNT(obj);
|
||||
default:
|
||||
if (FL_TEST(obj, FL_EXIVAR)) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
|
||||
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
return gen_ivtbl_count(obj, ivtbl);
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
return gen_fields_tbl_count(obj, fields_tbl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -4281,17 +4281,17 @@ rb_iv_set(VALUE obj, const char *name, VALUE val)
|
||||
}
|
||||
|
||||
static VALUE *
|
||||
class_ivar_set_shape_ivptr(VALUE obj, void *_data)
|
||||
class_ivar_set_shape_fields(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
|
||||
return RCLASS_IVPTR(obj);
|
||||
return RCLASS_FIELDS(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
class_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *_data)
|
||||
class_ivar_set_shape_resize_fields(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *_data)
|
||||
{
|
||||
REALLOC_N(RCLASS_IVPTR(obj), VALUE, new_capa);
|
||||
REALLOC_N(RCLASS_FIELDS(obj), VALUE, new_capa);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4311,7 +4311,7 @@ class_ivar_set_too_complex_table(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex(obj));
|
||||
|
||||
return RCLASS_IV_HASH(obj);
|
||||
return RCLASS_FIELDS_HASH(obj);
|
||||
}
|
||||
|
||||
int
|
||||
@ -4324,8 +4324,8 @@ rb_class_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
existing = general_ivar_set(obj, id, val, NULL,
|
||||
class_ivar_set_shape_ivptr,
|
||||
class_ivar_set_shape_resize_ivptr,
|
||||
class_ivar_set_shape_fields,
|
||||
class_ivar_set_shape_resize_fields,
|
||||
class_ivar_set_set_shape,
|
||||
class_ivar_set_transition_too_complex,
|
||||
class_ivar_set_too_complex_table).existing;
|
||||
@ -4344,13 +4344,13 @@ tbl_copy_i(ID key, VALUE val, st_data_t dest)
|
||||
}
|
||||
|
||||
void
|
||||
rb_iv_tbl_copy(VALUE dst, VALUE src)
|
||||
rb_fields_tbl_copy(VALUE dst, VALUE src)
|
||||
{
|
||||
RUBY_ASSERT(rb_type(dst) == rb_type(src));
|
||||
RUBY_ASSERT(RB_TYPE_P(dst, T_CLASS) || RB_TYPE_P(dst, T_MODULE));
|
||||
|
||||
RUBY_ASSERT(rb_shape_get_shape(dst)->type == SHAPE_ROOT);
|
||||
RUBY_ASSERT(!RCLASS_IVPTR(dst));
|
||||
RUBY_ASSERT(!RCLASS_FIELDS(dst));
|
||||
|
||||
rb_ivar_foreach(src, tbl_copy_i, dst);
|
||||
}
|
||||
|
10
variable.h
10
variable.h
@ -12,14 +12,14 @@
|
||||
|
||||
#include "shape.h"
|
||||
|
||||
struct gen_ivtbl {
|
||||
struct gen_fields_tbl {
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
uint16_t shape_id;
|
||||
#endif
|
||||
union {
|
||||
struct {
|
||||
uint32_t numiv;
|
||||
VALUE ivptr[1];
|
||||
uint32_t fields_count;
|
||||
VALUE fields[1];
|
||||
} shape;
|
||||
struct {
|
||||
st_table *table;
|
||||
@ -27,13 +27,13 @@ struct gen_ivtbl {
|
||||
} as;
|
||||
};
|
||||
|
||||
int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **);
|
||||
int rb_ivar_generic_fields_tbl_lookup(VALUE obj, struct gen_fields_tbl **);
|
||||
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
shape_id_t rb_generic_shape_id(VALUE obj);
|
||||
#endif
|
||||
|
||||
void rb_free_rb_global_tbl(void);
|
||||
void rb_free_generic_iv_tbl_(void);
|
||||
void rb_free_generic_fields_tbl_(void);
|
||||
|
||||
#endif /* RUBY_TOPLEVEL_VARIABLE_H */
|
||||
|
2
vm.c
2
vm.c
@ -3169,7 +3169,7 @@ ruby_vm_destruct(rb_vm_t *vm)
|
||||
if (objspace) {
|
||||
if (rb_free_at_exit) {
|
||||
rb_objspace_free_objects(objspace);
|
||||
rb_free_generic_iv_tbl_();
|
||||
rb_free_generic_fields_tbl_();
|
||||
rb_free_default_rand_key();
|
||||
if (th && vm->fork_gen == 0) {
|
||||
/* If we have forked, main_thread may not be the initial thread */
|
||||
|
@ -1230,7 +1230,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_OBJECT:
|
||||
ivar_list = ROBJECT_IVPTR(obj);
|
||||
ivar_list = ROBJECT_FIELDS(obj);
|
||||
VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true);
|
||||
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
@ -1256,7 +1256,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
|
||||
}
|
||||
}
|
||||
|
||||
ivar_list = RCLASS_IVPTR(obj);
|
||||
ivar_list = RCLASS_FIELDS(obj);
|
||||
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
shape_id = RCLASS_SHAPE_ID(obj);
|
||||
@ -1266,12 +1266,12 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
|
||||
}
|
||||
default:
|
||||
if (FL_TEST_RAW(obj, FL_EXIVAR)) {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
rb_gen_ivtbl_get(obj, id, &ivtbl);
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
rb_gen_fields_tbl_get(obj, id, &fields_tbl);
|
||||
#if !SHAPE_IN_BASIC_FLAGS
|
||||
shape_id = ivtbl->shape_id;
|
||||
shape_id = fields_tbl->shape_id;
|
||||
#endif
|
||||
ivar_list = ivtbl->as.shape.ivptr;
|
||||
ivar_list = fields_tbl->as.shape.fields;
|
||||
}
|
||||
else {
|
||||
return default_value;
|
||||
@ -1335,17 +1335,17 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = (st_table *)RCLASS_IVPTR(obj);
|
||||
table = (st_table *)RCLASS_FIELDS(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
table = ROBJECT_IV_HASH(obj);
|
||||
table = ROBJECT_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
default: {
|
||||
struct gen_ivtbl *ivtbl;
|
||||
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
|
||||
table = ivtbl->as.complex.table;
|
||||
struct gen_fields_tbl *fields_tbl;
|
||||
if (rb_gen_fields_tbl_get(obj, 0, &fields_tbl)) {
|
||||
table = fields_tbl->as.complex.table;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1469,7 +1469,7 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i
|
||||
shape_id_t shape_id = rb_generic_shape_id(obj);
|
||||
#endif
|
||||
|
||||
struct gen_ivtbl *ivtbl = 0;
|
||||
struct gen_fields_tbl *fields_tbl = 0;
|
||||
|
||||
// Cache hit case
|
||||
if (shape_id == dest_shape_id) {
|
||||
@ -1490,17 +1490,17 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i
|
||||
return Qundef;
|
||||
}
|
||||
|
||||
rb_gen_ivtbl_get(obj, 0, &ivtbl);
|
||||
rb_gen_fields_tbl_get(obj, 0, &fields_tbl);
|
||||
|
||||
if (shape_id != dest_shape_id) {
|
||||
#if SHAPE_IN_BASIC_FLAGS
|
||||
RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
|
||||
#else
|
||||
ivtbl->shape_id = dest_shape_id;
|
||||
fields_tbl->shape_id = dest_shape_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
RB_OBJ_WRITE(obj, &ivtbl->as.shape.ivptr[index], val);
|
||||
RB_OBJ_WRITE(obj, &fields_tbl->as.shape.fields[index], val);
|
||||
|
||||
RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
|
||||
|
||||
@ -1544,7 +1544,7 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
|
||||
break;
|
||||
}
|
||||
|
||||
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||
VALUE *ptr = ROBJECT_FIELDS(obj);
|
||||
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
|
||||
RB_OBJ_WRITE(obj, &ptr[index], val);
|
||||
|
2
yjit.c
2
yjit.c
@ -40,7 +40,7 @@
|
||||
|
||||
// Field offsets for the RObject struct
|
||||
enum robject_offsets {
|
||||
ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr),
|
||||
ROBJECT_OFFSET_AS_HEAP_FIELDS = offsetof(struct RObject, as.heap.fields),
|
||||
ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary),
|
||||
};
|
||||
|
||||
|
@ -2938,7 +2938,7 @@ fn gen_get_ivar(
|
||||
}
|
||||
Some(ivar_index) => {
|
||||
if embed_test_result {
|
||||
// See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
|
||||
// See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
|
||||
|
||||
// Load the variable
|
||||
let offs = ROBJECT_OFFSET_AS_ARY as i32 + (ivar_index * SIZEOF_VALUE) as i32;
|
||||
@ -2951,7 +2951,7 @@ fn gen_get_ivar(
|
||||
// Compile time value is *not* embedded.
|
||||
|
||||
// Get a pointer to the extended table
|
||||
let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR as i32));
|
||||
let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_FIELDS as i32));
|
||||
|
||||
// Read the ivar from the extended table
|
||||
let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index) as i32);
|
||||
@ -3020,7 +3020,7 @@ fn gen_write_iv(
|
||||
// Compile time value is *not* embedded.
|
||||
|
||||
// Get a pointer to the extended table
|
||||
let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR as i32));
|
||||
let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_FIELDS as i32));
|
||||
|
||||
// Write the ivar in to the extended table
|
||||
let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index) as i32);
|
||||
@ -3126,7 +3126,7 @@ fn gen_set_ivar(
|
||||
let needs_extension = unsafe { (*current_shape).capacity != (*next_shape).capacity };
|
||||
|
||||
// We can write to the object, but we need to transition the shape
|
||||
let ivar_index = unsafe { (*current_shape).next_iv_index } as usize;
|
||||
let ivar_index = unsafe { (*current_shape).next_field_index } as usize;
|
||||
|
||||
let needs_extension = if needs_extension {
|
||||
Some((current_capacity, unsafe { (*next_shape).capacity }))
|
||||
|
4
yjit/src/cruby_bindings.inc.rs
generated
4
yjit/src/cruby_bindings.inc.rs
generated
@ -648,7 +648,7 @@ pub type redblack_node_t = redblack_node;
|
||||
pub struct rb_shape {
|
||||
pub edges: *mut rb_id_table,
|
||||
pub edge_name: ID,
|
||||
pub next_iv_index: attr_index_t,
|
||||
pub next_field_index: attr_index_t,
|
||||
pub capacity: attr_index_t,
|
||||
pub type_: u8,
|
||||
pub heap_index: u8,
|
||||
@ -973,7 +973,7 @@ pub const DEFINED_REF: defined_type = 15;
|
||||
pub const DEFINED_FUNC: defined_type = 16;
|
||||
pub const DEFINED_CONST_FROM: defined_type = 17;
|
||||
pub type defined_type = u32;
|
||||
pub const ROBJECT_OFFSET_AS_HEAP_IVPTR: robject_offsets = 16;
|
||||
pub const ROBJECT_OFFSET_AS_HEAP_FIELDS: robject_offsets = 16;
|
||||
pub const ROBJECT_OFFSET_AS_ARY: robject_offsets = 16;
|
||||
pub type robject_offsets = u32;
|
||||
pub const RUBY_OFFSET_RSTRING_LEN: rstring_offsets = 16;
|
||||
|
2
zjit/src/cruby_bindings.inc.rs
generated
2
zjit/src/cruby_bindings.inc.rs
generated
@ -405,7 +405,7 @@ pub type redblack_node_t = redblack_node;
|
||||
pub struct rb_shape {
|
||||
pub edges: *mut rb_id_table,
|
||||
pub edge_name: ID,
|
||||
pub next_iv_index: attr_index_t,
|
||||
pub next_field_index: attr_index_t,
|
||||
pub capacity: attr_index_t,
|
||||
pub type_: u8,
|
||||
pub heap_index: u8,
|
||||
|
Loading…
x
Reference in New Issue
Block a user