8000 Add SHAPE_ID_HAS_IVAR_MASK for quick ivar check · ruby/ruby@a99d941 · GitHub
[go: up one dir, main page]

Skip to content

Commit a99d941

Browse files
committed
Add SHAPE_ID_HAS_IVAR_MASK for quick ivar check
This allow checking if an object has ivars with just a shape_id mask.
1 parent fb0dbbc commit a99d941

File tree

7 files changed

+41
-13
lines changed

7 files changed

+41
-13
lines changed

internal/string.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum ruby_rstring_private_flags {
3030
#endif
3131

3232
/* string.c */
33+
VALUE rb_str_dup_m(VALUE str);
3334
VALUE rb_fstring(VALUE);
3435
VALUE rb_fstring_cstr(const char *str);
3536
VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc);

shape.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,23 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
12341234
}
12351235
}
12361236

1237+
// Make sure SHAPE_ID_HAS_IVAR_MASK is valid.
1238+
if (rb_shape_too_complex_p(shape_id)) {
1239+
RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
1240+
}
1241+
else {
1242+
attr_index_t ivar_count = RSHAPE_LEN(shape_id);
1243+
if (has_object_id) {
1244+
ivar_count--;
1245+
}
1246+
if (ivar_count) {
1247+
RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
1248+
}
1249+
else {
1250+
RUBY_ASSERT(!(shape_id & SHAPE_ID_HAS_IVAR_MASK));
1251+
}
1252+
}
1253+
12371254
uint8_t flags_heap_index = rb_shape_heap_index(shape_id);
12381255
if (RB_TYPE_P(obj, T_OBJECT)) {
12391256
size_t shape_id_slot_size = rb_shape_tree.capacities[flags_heap_index - 1] * sizeof(VALUE) + sizeof(struct RBasic);
@@ -1524,14 +1541,15 @@ Init_default_shapes(void)
15241541
root->type = SHAPE_ROOT;
15251542
rb_shape_tree.root_shape = root;
15261543
RUBY_ASSERT(raw_shape_id(rb_shape_tree.root_shape) == ROOT_SHAPE_ID);
1544+
RUBY_ASSERT(!(raw_shape_id(rb_shape_tree.root_shape) & SHAPE_ID_HAS_IVAR_MASK));
15271545

15281546
bool dontcare;
15291547
rb_shape_t *root_with_obj_id = get_next_shape_internal(root, id_object_id, SHAPE_OBJ_ID, &dontcare, true);
15301548
RUBY_ASSERT(raw_shape_id(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
15311549
RUBY_ASSERT(root_with_obj_id->type == SHAPE_OBJ_ID);
15321550
RUBY_ASSERT(root_with_obj_id->edge_name == id_object_id);
15331551
RUBY_ASSERT(root_with_obj_id->next_field_index == 1);
1534-
(void)root_with_obj_id;
1552+
RUBY_ASSERT(!(raw_shape_id(root_with_obj_id) & SHAPE_ID_HAS_IVAR_MASK));
15351553
}
15361554

15371555
void

shape.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
2323
#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
2424
#define SHAPE_ID_HEAP_INDEX_MASK (SHAPE_ID_HEAP_INDEX_MAX << SHAPE_ID_HEAP_INDEX_OFFSET)
2525

26+
// This masks allows to check if a shape_id contains any ivar.
27+
// It rely on ROOT_SHAPE_WITH_OBJ_ID==1.
28+
#define SHAPE_ID_HAS_IVAR_MASK (SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1))
29+
2630
// The interpreter doesn't care about frozen status or slot size when reading ivars.
2731
// So we normalize shape_id by clearing these bits to improve cache hits.
2832
// JITs however might care about it.
@@ -327,6 +331,18 @@ rb_shape_obj_has_id(VALUE obj)
327331
return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
328332
}
329333

334+
static inline bool
335+
rb_shape_has_ivars(shape_id_t shape_id)
336+
{
337+
return shape_id & SHAPE_ID_HAS_IVAR_MASK;
338+
}
339+
340+
static inline bool
341+
rb_shape_obj_has_ivars(VALUE obj)
342+
{
343+
return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
344+
}
345+
330346
// For ext/objspace
331347
RUBY_SYMBOL_EXPORT_BEGIN
332348
typedef void each_shape_callback(shape_id_t shape_id, void *data);

string.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,7 @@ fstring_hash(VALUE str)
388388
static inline bool
389389
BARE_STRING_P(VALUE str)
390390
{
391-
if (RBASIC_CLASS(str) != rb_cString) return false;
392-
393-
if (FL_TEST_RAW(str, FL_EXIVAR)) {
394-
return rb_ivar_count(str) == 0;
395-
}
396-
return true;
391+
return RBASIC_CLASS(str) == rb_cString && !rb_shape_obj_has_ivars(str);
397392
}
398393

399394
static inline st_index_t
@@ -2316,7 +2311,7 @@ VALUE
23162311
rb_str_dup_m(VALUE str)
23172312
{
23182313
if (LIKELY(BARE_STRING_P(str))) {
2319-
return str_duplicate(rb_obj_class(str), str);
2314+
return str_duplicate(rb_cString, str);
23202315
}
23212316
else {
23222317
return rb_obj_dup(str);

yjit/bindgen/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ fn main() {
228228
.allowlist_function("rb_obj_as_string_result")
229229
.allowlist_function("rb_str_byte_substr")
230230
.allowlist_function("rb_str_substr_two_fixnums")
231+
.allowlist_function("rb_str_dup_m")
231232

232233
// From include/ruby/internal/intern/parse.h
233234
.allowlist_function("rb_backref_get")

yjit/src/codegen.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6275,16 +6275,12 @@ fn jit_rb_str_dup(
62756275

62766276
jit_prepare_call_with_gc(jit, asm);
62776277

6278-
// Check !FL_ANY_RAW(str, FL_EXIVAR), which is part of BARE_STRING_P.
62796278
let recv_opnd = asm.stack_pop(1);
62806279
let recv_opnd = asm.load(recv_opnd);
6281-
let flags_opnd = Opnd::mem(64, recv_opnd, RUBY_OFFSET_RBASIC_FLAGS);
6282-
asm.test(flags_opnd, Opnd::Imm(RUBY_FL_EXIVAR as i64));
6283-
asm.jnz(Target::side_exit(Counter::send_str_dup_exivar));
62846280

62856281
// Call rb_str_dup
62866282
let stack_ret = asm.stack_push(Type::CString);
6287-
let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
6283+
let ret_opnd = asm.ccall(rb_str_dup_m as *const u8, vec![recv_opnd]);
62886284
asm.mov(stack_ret, ret_opnd);
62896285

62906286
true

yjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0