mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Add SHAPE_ID_HAS_IVAR_MASK for quick ivar check
This allow checking if an object has ivars with just a shape_id mask.
This commit is contained in:
parent
fb0dbbc0e6
commit
a99d941cac
Notes:
git
2025-06-13 17:46:42 +00:00
7 changed files with 41 additions and 13 deletions
|
@ -30,6 +30,7 @@ enum ruby_rstring_private_flags {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* string.c */
|
/* string.c */
|
||||||
|
VALUE rb_str_dup_m(VALUE str);
|
||||||
VALUE rb_fstring(VALUE);
|
VALUE rb_fstring(VALUE);
|
||||||
VALUE rb_fstring_cstr(const char *str);
|
VALUE rb_fstring_cstr(const char *str);
|
||||||
VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc);
|
VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc);
|
||||||
|
|
20
shape.c
20
shape.c
|
@ -1234,6 +1234,23 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure SHAPE_ID_HAS_IVAR_MASK is valid.
|
||||||
|
if (rb_shape_too_complex_p(shape_id)) {
|
||||||
|
RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
attr_index_t ivar_count = RSHAPE_LEN(shape_id);
|
||||||
|
if (has_object_id) {
|
||||||
|
ivar_count--;
|
||||||
|
}
|
||||||
|
if (ivar_count) {
|
||||||
|
RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RUBY_ASSERT(!(shape_id & SHAPE_ID_HAS_IVAR_MASK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t flags_heap_index = rb_shape_heap_index(shape_id);
|
uint8_t flags_heap_index = rb_shape_heap_index(shape_id);
|
||||||
if (RB_TYPE_P(obj, T_OBJECT)) {
|
if (RB_TYPE_P(obj, T_OBJECT)) {
|
||||||
size_t shape_id_slot_size = rb_shape_tree.capacities[flags_heap_index - 1] * sizeof(VALUE) + sizeof(struct RBasic);
|
size_t shape_id_slot_size = rb_shape_tree.capacities[flags_heap_index - 1] * sizeof(VALUE) + sizeof(struct RBasic);
|
||||||
|
@ -1524,6 +1541,7 @@ Init_default_shapes(void)
|
||||||
root->type = SHAPE_ROOT;
|
root->type = SHAPE_ROOT;
|
||||||
rb_shape_tree.root_shape = root;
|
rb_shape_tree.root_shape = root;
|
||||||
RUBY_ASSERT(raw_shape_id(rb_shape_tree.root_shape) == ROOT_SHAPE_ID);
|
RUBY_ASSERT(raw_shape_id(rb_shape_tree.root_shape) == ROOT_SHAPE_ID);
|
||||||
|
RUBY_ASSERT(!(raw_shape_id(rb_shape_tree.root_shape) & SHAPE_ID_HAS_IVAR_MASK));
|
||||||
|
|
||||||
bool dontcare;
|
bool dontcare;
|
||||||
rb_shape_t *root_with_obj_id = get_next_shape_internal(root, id_object_id, SHAPE_OBJ_ID, &dontcare, true);
|
rb_shape_t *root_with_obj_id = get_next_shape_internal(root, id_object_id, SHAPE_OBJ_ID, &dontcare, true);
|
||||||
|
@ -1531,7 +1549,7 @@ Init_default_shapes(void)
|
||||||
RUBY_ASSERT(root_with_obj_id->type == SHAPE_OBJ_ID);
|
RUBY_ASSERT(root_with_obj_id->type == SHAPE_OBJ_ID);
|
||||||
RUBY_ASSERT(root_with_obj_id->edge_name == id_object_id);
|
RUBY_ASSERT(root_with_obj_id->edge_name == id_object_id);
|
||||||
RUBY_ASSERT(root_with_obj_id->next_field_index == 1);
|
RUBY_ASSERT(root_with_obj_id->next_field_index == 1);
|
||||||
(void)root_with_obj_id;
|
RUBY_ASSERT(!(raw_shape_id(root_with_obj_id) & SHAPE_ID_HAS_IVAR_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
16
shape.h
16
shape.h
|
@ -23,6 +23,10 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
|
||||||
#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
|
#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
|
||||||
#define SHAPE_ID_HEAP_INDEX_MASK (SHAPE_ID_HEAP_INDEX_MAX << SHAPE_ID_HEAP_INDEX_OFFSET)
|
#define SHAPE_ID_HEAP_INDEX_MASK (SHAPE_ID_HEAP_INDEX_MAX << SHAPE_ID_HEAP_INDEX_OFFSET)
|
||||||
|
|
||||||
|
// This masks allows to check if a shape_id contains any ivar.
|
||||||
|
// It rely on ROOT_SHAPE_WITH_OBJ_ID==1.
|
||||||
|
#define SHAPE_ID_HAS_IVAR_MASK (SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1))
|
||||||
|
|
||||||
// The interpreter doesn't care about frozen status or slot size when reading ivars.
|
// The interpreter doesn't care about frozen status or slot size when reading ivars.
|
||||||
// So we normalize shape_id by clearing these bits to improve cache hits.
|
// So we normalize shape_id by clearing these bits to improve cache hits.
|
||||||
// JITs however might care about it.
|
// JITs however might care about it.
|
||||||
|
@ -327,6 +331,18 @@ rb_shape_obj_has_id(VALUE obj)
|
||||||
return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
|
return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
rb_shape_has_ivars(shape_id_t shape_id)
|
||||||
|
{
|
||||||
|
return shape_id & SHAPE_ID_HAS_IVAR_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
rb_shape_obj_has_ivars(VALUE obj)
|
||||||
|
{
|
||||||
|
return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
|
||||||
|
}
|
||||||
|
|
||||||
// For ext/objspace
|
// For ext/objspace
|
||||||
RUBY_SYMBOL_EXPORT_BEGIN
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||||||
typedef void each_shape_callback(shape_id_t shape_id, void *data);
|
typedef void each_shape_callback(shape_id_t shape_id, void *data);
|
||||||
|
|
9
string.c
9
string.c
|
@ -388,12 +388,7 @@ fstring_hash(VALUE str)
|
||||||
static inline bool
|
static inline bool
|
||||||
BARE_STRING_P(VALUE str)
|
BARE_STRING_P(VALUE str)
|
||||||
{
|
{
|
||||||
if (RBASIC_CLASS(str) != rb_cString) return false;
|
return RBASIC_CLASS(str) == rb_cString && !rb_shape_obj_has_ivars(str);
|
||||||
|
|
||||||
if (FL_TEST_RAW(str, FL_EXIVAR)) {
|
|
||||||
return rb_ivar_count(str) == 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline st_index_t
|
static inline st_index_t
|
||||||
|
@ -2316,7 +2311,7 @@ VALUE
|
||||||
rb_str_dup_m(VALUE str)
|
rb_str_dup_m(VALUE str)
|
||||||
{
|
{
|
||||||
if (LIKELY(BARE_STRING_P(str))) {
|
if (LIKELY(BARE_STRING_P(str))) {
|
||||||
return str_duplicate(rb_obj_class(str), str);
|
return str_duplicate(rb_cString, str);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return rb_obj_dup(str);
|
return rb_obj_dup(str);
|
||||||
|
|
|
@ -228,6 +228,7 @@ fn main() {
|
||||||
.allowlist_function("rb_obj_as_string_result")
|
.allowlist_function("rb_obj_as_string_result")
|
||||||
.allowlist_function("rb_str_byte_substr")
|
.allowlist_function("rb_str_byte_substr")
|
||||||
.allowlist_function("rb_str_substr_two_fixnums")
|
.allowlist_function("rb_str_substr_two_fixnums")
|
||||||
|
.allowlist_function("rb_str_dup_m")
|
||||||
|
|
||||||
// From include/ruby/internal/intern/parse.h
|
// From include/ruby/internal/intern/parse.h
|
||||||
.allowlist_function("rb_backref_get")
|
.allowlist_function("rb_backref_get")
|
||||||
|
|
|
@ -6275,16 +6275,12 @@ fn jit_rb_str_dup(
|
||||||
|
|
||||||
jit_prepare_call_with_gc(jit, asm);
|
jit_prepare_call_with_gc(jit, asm);
|
||||||
|
|
||||||
// Check !FL_ANY_RAW(str, FL_EXIVAR), which is part of BARE_STRING_P.
|
|
||||||
let recv_opnd = asm.stack_pop(1);
|
let recv_opnd = asm.stack_pop(1);
|
||||||
let recv_opnd = asm.load(recv_opnd);
|
let recv_opnd = asm.load(recv_opnd);
|
||||||
let flags_opnd = Opnd::mem(64, recv_opnd, RUBY_OFFSET_RBASIC_FLAGS);
|
|
||||||
asm.test(flags_opnd, Opnd::Imm(RUBY_FL_EXIVAR as i64));
|
|
||||||
asm.jnz(Target::side_exit(Counter::send_str_dup_exivar));
|
|
||||||
|
|
||||||
// Call rb_str_dup
|
// Call rb_str_dup
|
||||||
let stack_ret = asm.stack_push(Type::CString);
|
let stack_ret = asm.stack_push(Type::CString);
|
||||||
let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
|
let ret_opnd = asm.ccall(rb_str_dup_m as *const u8, vec![recv_opnd]);
|
||||||
asm.mov(stack_ret, ret_opnd);
|
asm.mov(stack_ret, ret_opnd);
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
1
yjit/src/cruby_bindings.inc.rs
generated
1
yjit/src/cruby_bindings.inc.rs
generated
|
@ -1119,6 +1119,7 @@ extern "C" {
|
||||||
pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE;
|
pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE;
|
||||||
pub fn rb_ensure_iv_list_size(obj: VALUE, current_len: u32, newsize: u32);
|
pub fn rb_ensure_iv_list_size(obj: VALUE, current_len: u32, newsize: u32);
|
||||||
pub fn rb_vm_barrier();
|
pub fn rb_vm_barrier();
|
||||||
|
pub fn rb_str_dup_m(str_: VALUE) -> VALUE;
|
||||||
pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE;
|
pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE;
|
||||||
pub fn rb_str_substr_two_fixnums(
|
pub fn rb_str_substr_two_fixnums(
|
||||||
str_: VALUE,
|
str_: VALUE,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue