Skip to content

Commit 96a0e92

Browse files
committed
Use all 32bits of shape_id_t on all platforms
Followup: ruby#13341 / [Feature #21353] Even thought `shape_id_t` has been make 32bits, we were still limited to use only the lower 16 bits because they had to fit alongside `attr_index_t` inside a `uintptr_t` in inline caches. By enlarging inline caches we can unlock the full 32bits on all platforms, allowing to use these extra bits for tagging.
1 parent 5f24741 commit 96a0e92

7 files changed

Lines changed: 79 additions & 47 deletions

File tree

shape.h

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,22 @@
33

44
#include "internal/gc.h"
55

6-
#if (SIZEOF_UINT64_T <= SIZEOF_VALUE)
7-
86
#define SIZEOF_SHAPE_T 4
9-
typedef uint32_t attr_index_t;
10-
typedef uint32_t shape_id_t;
11-
# define SHAPE_ID_NUM_BITS 32
12-
13-
#else
14-
15-
#define SIZEOF_SHAPE_T 2
167
typedef uint16_t attr_index_t;
17-
typedef uint16_t shape_id_t;
18-
# define SHAPE_ID_NUM_BITS 16
19-
20-
#endif
8+
typedef uint32_t shape_id_t;
9+
#define SHAPE_ID_NUM_BITS 32
2110

2211
typedef uint32_t redblack_id_t;
2312

2413
#define SHAPE_MAX_FIELDS (attr_index_t)(-1)
2514

26-
# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
15+
#define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
16+
#define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
2717

28-
# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
18+
#define SHAPE_MAX_VARIATIONS 8
2919

30-
# define SHAPE_MAX_VARIATIONS 8
31-
32-
# define INVALID_SHAPE_ID (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
33-
#define ATTR_INDEX_NOT_SET (attr_index_t)-1
20+
#define INVALID_SHAPE_ID ((shape_id_t)-1)
21+
#define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
3422

3523
#define ROOT_SHAPE_ID 0x0
3624
#define SPECIAL_CONST_SHAPE_ID 0x1
@@ -44,13 +32,13 @@ typedef struct redblack_node redblack_node_t;
4432
struct rb_shape {
4533
VALUE edges; // id_table from ID (ivar) to next shape
4634
ID edge_name; // ID (ivar) for transition from parent to rb_shape
35+
redblack_node_t *ancestor_index;
36+
shape_id_t parent_id;
4737
attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id`
4838
attr_index_t capacity; // Total capacity of the object with this shape
4939
uint8_t type;
5040
uint8_t heap_index;
5141
uint8_t flags;
52-
shape_id_t parent_id;
53-
redblack_node_t *ancestor_index;
5442
};
5543

5644
typedef struct rb_shape rb_shape_t;
@@ -82,6 +70,14 @@ typedef struct {
8270
} rb_shape_tree_t;
8371
RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;
8472

73+
union rb_attr_index_cache {
74+
uint64_t pack;
75+
struct {
76+
shape_id_t shape_id;
77+
attr_index_t index;
78+
} unpack;
79+
};
80+
8581
static inline rb_shape_tree_t *
8682
rb_current_shape_tree(void)
8783
{

vm_callinfo.h

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ struct rb_callcache {
289289

290290
union {
291291
struct {
292-
uintptr_t value; // Shape ID in upper bits, index in lower bits
292+
uint64_t value; // Shape ID in upper bits, index in lower bits
293293
} attr;
294294
const enum method_missing_reason method_missing_reason; /* used by method_missing */
295295
VALUE v;
@@ -415,25 +415,41 @@ vm_cc_call(const struct rb_callcache *cc)
415415
return cc->call_;
416416
}
417417

418+
static inline uint64_t
419+
vm_uint64_t_atomic_read(const uint64_t *value)
420+
{
421+
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
422+
return __atomic_load_n(value, __ATOMIC_RELAXED);
423+
#elif defined(_WIN32)
424+
uint64_t val = *value;
425+
return InterlockedCompareExchange64(value, val, val);
426+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
427+
uint64_t val = *value;
428+
return atomic_cas_64(value, val, val);
429+
#else
430+
return *value;
431+
#endif
432+
}
433+
418434
static inline void
419-
vm_unpack_shape_and_index(uintptr_t cache_value, shape_id_t *shape_id, attr_index_t *index)
435+
vm_unpack_shape_and_index(const uint64_t *cache_value_ptr, shape_id_t *shape_id, attr_index_t *index)
420436
{
421-
*shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
422-
*index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
437+
union rb_attr_index_cache cache;
438+
cache.pack = vm_uint64_t_atomic_read(cache_value_ptr);
439+
*shape_id = cache.unpack.shape_id;
440+
*index = cache.unpack.index - 1;
423441
}
424442

425443
static inline void
426444
vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t *shape_id, attr_index_t *index)
427445
{
428-
// Atomically read uintptr_t
429-
vm_unpack_shape_and_index(cc->aux_.attr.value, shape_id, index);
446+
vm_unpack_shape_and_index(&cc->aux_.attr.value, shape_id, index);
430447
}
431448

432449
static inline void
433450
vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t *shape_id, attr_index_t *index)
434451
{
435-
// Atomically read uintptr_t
436-
vm_unpack_shape_and_index(ic->value, shape_id, index);
452+
vm_unpack_shape_and_index(&ic->value, shape_id, index);
437453
}
438454

439455
static inline unsigned int
@@ -470,16 +486,22 @@ set_vm_cc_ivar(const struct rb_callcache *cc)
470486
*(VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
471487
}
472488

473-
static inline uintptr_t
489+
static inline uint64_t
474490
vm_pack_shape_and_index(shape_id_t shape_id, attr_index_t index)
475491
{
476-
return (attr_index_t)(index + 1) | ((uintptr_t)(shape_id) << SHAPE_FLAG_SHIFT);
492+
union rb_attr_index_cache cache = {
493+
.unpack = {
494+
.shape_id = shape_id,
495+
.index = index + 1,
496+
}
497+
};
498+
return cache.pack;
477499
}
478500

479501
static inline void
480502
vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id)
481503
{
482-
uintptr_t *attr_value = (uintptr_t *)&cc->aux_.attr.value;
504+
uint64_t *attr_value = (uint64_t *)&cc->aux_.attr.value;
483505
if (!vm_cc_markable(cc)) {
484506
*attr_value = vm_pack_shape_and_index(INVALID_SHAPE_ID, ATTR_INDEX_NOT_SET);
485507
return;
@@ -496,16 +518,30 @@ vm_cc_ivar_p(const struct rb_callcache *cc)
496518
return (cc->flags & VM_CALLCACHE_IVAR) != 0;
497519
}
498520

521+
static inline void
522+
vm_uint64_t_atomic_write(uint64_t *address, uint64_t value)
523+
{
524+
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
525+
__atomic_store_n(address, value, __ATOMIC_RELAXED);
526+
#elif defined(_WIN32)
527+
InterlockedExchange64(address, value);
528+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
529+
atomic_swap_64(address, value);
530+
#else
531+
*address = value;
532+
#endif
533+
}
534+
499535
static inline void
500536
vm_ic_attr_index_set(const rb_iseq_t *iseq, const struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t dest_shape_id)
501537
{
502-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(dest_shape_id, index);
538+
vm_uint64_t_atomic_write((uint64_t *)&ic->value, vm_pack_shape_and_index(dest_shape_id, index));
503539
}
504540

505541
static inline void
506542
vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
507543
{
508-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET);
544+
vm_uint64_t_atomic_write((uint64_t *)&ic->value, vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET));
509545
}
510546

511547
static inline void

vm_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ struct iseq_inline_constant_cache {
288288
};
289289

290290
struct iseq_inline_iv_cache_entry {
291-
uintptr_t value; // attr_index in lower bits, dest_shape_id in upper bits
291+
uint64_t value; // attr_index in lower bits, dest_shape_id in upper bits
292292
ID iv_set_name;
293293
};
294294

vm_insnhelper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4774,7 +4774,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
47744774
.call_ = cc->call_,
47754775
.aux_ = {
47764776
.attr = {
4777-
.value = INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT,
4777+
.value = vm_pack_shape_and_index(INVALID_SHAPE_ID, ATTR_INDEX_NOT_SET),
47784778
}
47794779
},
47804780
});

yjit/src/codegen.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2904,7 +2904,7 @@ fn gen_get_ivar(
29042904

29052905
let ivar_index = unsafe {
29062906
let shape_id = comptime_receiver.shape_id_of();
2907-
let mut ivar_index: u32 = 0;
2907+
let mut ivar_index: u16 = 0;
29082908
if rb_shape_get_iv_index(shape_id, ivar_name, &mut ivar_index) {
29092909
Some(ivar_index as usize)
29102910
} else {
@@ -3106,7 +3106,7 @@ fn gen_set_ivar(
31063106
let shape_too_complex = comptime_receiver.shape_too_complex();
31073107
let ivar_index = if !shape_too_complex {
31083108
let shape_id = comptime_receiver.shape_id_of();
3109-
let mut ivar_index: u32 = 0;
3109+
let mut ivar_index: u16 = 0;
31103110
if unsafe { rb_shape_get_iv_index(shape_id, ivar_name, &mut ivar_index) } {
31113111
Some(ivar_index as usize)
31123112
} else {
@@ -3395,7 +3395,7 @@ fn gen_definedivar(
33953395

33963396
let shape_id = comptime_receiver.shape_id_of();
33973397
let ivar_exists = unsafe {
3398-
let mut ivar_index: u32 = 0;
3398+
let mut ivar_index: u16 = 0;
33993399
rb_shape_get_iv_index(shape_id, ivar_name, &mut ivar_index)
34003400
};
34013401

yjit/src/cruby_bindings.inc.rs

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

zjit/src/cruby_bindings.inc.rs

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

0 commit comments

Comments
 (0)