Skip to content

Commit e27404a

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 ea8b53a commit e27404a

File tree

8 files changed

+84
-49
lines changed

8 files changed

+84
-49
lines changed

ruby_atomic.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,36 @@ rbimpl_atomic_load_relaxed(rb_atomic_t *ptr)
3636
}
3737
#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load_relaxed(&(var))
3838

39+
static inline uint64_t
40+
rbimpl_atomic_u64_load_relaxed(const uint64_t *value)
41+
{
42+
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
43+
return __atomic_load_n(value, __ATOMIC_RELAXED);
44+
#elif defined(_WIN32)
45+
uint64_t val = *value;
46+
return InterlockedCompareExchange64(value, val, val);
47+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
48+
uint64_t val = *value;
49+
return atomic_cas_64(value, val, val);
50+
#else
51+
return *value;
52+
#endif
53+
}
54+
#define ATOMIC_U64_LOAD_RELAXED(var) rbimpl_atomic_u64_load_relaxed(&(var))
55+
56+
static inline void
57+
rbimpl_atomic_u64_set_relaxed(uint64_t *address, uint64_t value)
58+
{
59+
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
60+
__atomic_store_n(address, value, __ATOMIC_RELAXED);
61+
#elif defined(_WIN32)
62+
InterlockedExchange64(address, value);
63+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
64+
atomic_swap_64(address, value);
65+
#else
66+
*address = value;
67+
#endif
68+
}
69+
#define ATOMIC_U64_SET_RELAXED(var, val) rbimpl_atomic_u64_set_relaxed(&(var), val)
70+
3971
#endif

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: 22 additions & 15 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;
@@ -416,24 +416,25 @@ vm_cc_call(const struct rb_callcache *cc)
416416
}
417417

418418
static inline void
419-
vm_unpack_shape_and_index(uintptr_t cache_value, shape_id_t *shape_id, attr_index_t *index)
419+
vm_unpack_shape_and_index(const uint64_t cache_value, shape_id_t *shape_id, attr_index_t *index)
420420
{
421-
*shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
422-
*index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
421+
union rb_attr_index_cache cache = {
422+
.pack = cache_value,
423+
};
424+
*shape_id = cache.unpack.shape_id;
425+
*index = cache.unpack.index - 1;
423426
}
424427

425428
static inline void
426429
vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t *shape_id, attr_index_t *index)
427430
{
428-
// Atomically read uintptr_t
429-
vm_unpack_shape_and_index(cc->aux_.attr.value, shape_id, index);
431+
vm_unpack_shape_and_index(ATOMIC_U64_LOAD_RELAXED(cc->aux_.attr.value), shape_id, index);
430432
}
431433

432434
static inline void
433435
vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t *shape_id, attr_index_t *index)
434436
{
435-
// Atomically read uintptr_t
436-
vm_unpack_shape_and_index(ic->value, shape_id, index);
437+
vm_unpack_shape_and_index(ATOMIC_U64_LOAD_RELAXED(ic->value), shape_id, index);
437438
}
438439

439440
static inline unsigned int
@@ -470,16 +471,22 @@ set_vm_cc_ivar(const struct rb_callcache *cc)
470471
*(VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
471472
}
472473

473-
static inline uintptr_t
474+
static inline uint64_t
474475
vm_pack_shape_and_index(shape_id_t shape_id, attr_index_t index)
475476
{
476-
return (attr_index_t)(index + 1) | ((uintptr_t)(shape_id) << SHAPE_FLAG_SHIFT);
477+
union rb_attr_index_cache cache = {
478+
.unpack = {
479+
.shape_id = shape_id,
480+
.index = index + 1,
481+
}
482+
};
483+
return cache.pack;
477484
}
478485

479486
static inline void
480487
vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id)
481488
{
482-
uintptr_t *attr_value = (uintptr_t *)&cc->aux_.attr.value;
489+
uint64_t *attr_value = (uint64_t *)&cc->aux_.attr.value;
483490
if (!vm_cc_markable(cc)) {
484491
*attr_value = vm_pack_shape_and_index(INVALID_SHAPE_ID, ATTR_INDEX_NOT_SET);
485492
return;
@@ -497,15 +504,15 @@ vm_cc_ivar_p(const struct rb_callcache *cc)
497504
}
498505

499506
static inline void
500-
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)
507+
vm_ic_attr_index_set(const rb_iseq_t *iseq, struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t dest_shape_id)
501508
{
502-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(dest_shape_id, index);
509+
ATOMIC_U64_SET_RELAXED(ic->value, vm_pack_shape_and_index(dest_shape_id, index));
503510
}
504511

505512
static inline void
506-
vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
513+
vm_ic_attr_index_initialize(struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
507514
{
508-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET);
515+
ATOMIC_U64_SET_RELAXED(ic->value, vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET));
509516
}
510517

511518
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)