Skip to content

Commit e525a4c

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 52d85c0 commit e525a4c

7 files changed

Lines changed: 64 additions & 42 deletions

File tree

shape.h

Lines changed: 9 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)
27-
28-
# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - 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)
2917

30-
# define SHAPE_MAX_VARIATIONS 8
18+
#define SHAPE_MAX_VARIATIONS 8
3119

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;

vm_callinfo.h

Lines changed: 42 additions & 8 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,43 @@ 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 (SIZEOF_UINT64_T == SIZEOF_VALUE)
422+
// Atomically read pointer sized value.
423+
return *value;
424+
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
425+
return __atomic_load_n(value, __ATOMIC_RELAXED);
426+
#elif defined(_WIN32)
427+
uint64_t val = *value;
428+
return InterlockedCompareExchange64(value, val, val);
429+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
430+
uint64_t val = *value;
431+
return atomic_cas_64(value, val, val);
432+
#else
433+
return *value;
434+
#endif
435+
}
436+
418437
static inline void
419-
vm_unpack_shape_and_index(uintptr_t cache_value, shape_id_t *shape_id, attr_index_t *index)
438+
vm_unpack_shape_and_index(const uint64_t *cache_value_ptr, shape_id_t *shape_id, attr_index_t *index)
420439
{
440+
const uint64_t cache_value = vm_uint64_t_atomic_read(cache_value_ptr);
421441
*shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
422442
*index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
423443
}
424444

425445
static inline void
426446
vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t *shape_id, attr_index_t *index)
427447
{
428-
// Atomically read uintptr_t
429-
vm_unpack_shape_and_index(cc->aux_.attr.value, shape_id, index);
448+
vm_unpack_shape_and_index(&cc->aux_.attr.value, shape_id, index);
430449
}
431450

432451
static inline void
433452
vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t *shape_id, attr_index_t *index)
434453
{
435-
// Atomically read uintptr_t
436-
vm_unpack_shape_and_index(ic->value, shape_id, index);
454+
vm_unpack_shape_and_index(&ic->value, shape_id, index);
437455
}
438456

439457
static inline unsigned int
@@ -496,16 +514,32 @@ vm_cc_ivar_p(const struct rb_callcache *cc)
496514
return (cc->flags & VM_CALLCACHE_IVAR) != 0;
497515
}
498516

517+
static inline void
518+
vm_uint64_t_atomic_write(uint64_t *address, uint64_t value)
519+
{
520+
#if (SIZEOF_UINT64_T == SIZEOF_VALUE)
521+
*address = value;
522+
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
523+
__atomic_store_n(address, value, __ATOMIC_RELAXED);
524+
#elif defined(_WIN32)
525+
InterlockedExchange64(address, value);
526+
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
527+
atomic_swap_64(address, value);
528+
#else
529+
*address = value;
530+
#endif
531+
}
532+
499533
static inline void
500534
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)
501535
{
502-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(dest_shape_id, index);
536+
vm_uint64_t_atomic_write((uint64_t *)&ic->value, vm_pack_shape_and_index(dest_shape_id, index));
503537
}
504538

505539
static inline void
506540
vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
507541
{
508-
*(uintptr_t *)&ic->value = vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET);
542+
vm_uint64_t_atomic_write((uint64_t *)&ic->value, vm_pack_shape_and_index(shape_id, ATTR_INDEX_NOT_SET));
509543
}
510544

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