imemo_tmp_buffer: skip marking when useless

In many place ALLOC_V / ALLOCV_N is used as a safer `alloca`,
and to behave like stack memory, `ALLOCV` does scan its buffer
for references using `rb_gc_mark_locations`.

The problem is that it's quite slow, and in many cases, the
temporary buffer is known not to contain any references.

e.g. `ALLOCV_N(uint32_t, buf0, len)` can't possibly contain references,
as the element size is too small.
This commit is contained in:
Jean Boussier committed 2026-06-16 16:52:32 +02:00
1 parent 0384a27828
commit 78495ca415
4 files changed
+10 -37
Notes: git 2026-06-16 14:53:08 +00:00

No files matched your search

+4 -8
View File
@@ -57,6 +57,7 @@ rb_imemo_tmpbuf_new(void)
rb_gc_register_pinning_obj((VALUE)obj);
obj->marked = false;
obj->ptr = NULL;
obj->size = 0;
@@ -64,7 +65,7 @@ rb_imemo_tmpbuf_new(void)
}
void *
rb_alloc_tmp_buffer(volatile VALUE *store, long len)
rb_alloc_tmp_buffer(volatile VALUE *store, long len, bool marked)
{
if (len < 0) {
rb_raise(rb_eArgError, "negative buffer size (or size too big)");
@@ -75,18 +76,13 @@ rb_alloc_tmp_buffer(volatile VALUE *store, long len)
rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
*store = (VALUE)tmpbuf;
void *ptr = ruby_xmalloc(len);
tmpbuf->marked = marked;
tmpbuf->ptr = ptr;
tmpbuf->size = len;
return ptr;
}
void *
rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
{
return rb_alloc_tmp_buffer(store, (long)size);
}
void
rb_free_tmp_buffer(volatile VALUE *store)
{
@@ -556,7 +552,7 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_tmpbuf: {
const rb_imemo_tmpbuf_t *m = (const rb_imemo_tmpbuf_t *)obj;
if (!reference_updating) {
if (m->marked && !reference_updating) {
rb_gc_mark_locations(m->ptr, m->ptr + (m->size / sizeof(VALUE)));
}
+3 -26
View File
@@ -304,7 +304,7 @@ typedef uint128_t DSIZE_T;
#define RB_ALLOCV(v, n) \
((n) < RUBY_ALLOCV_LIMIT ? \
((v) = 0, alloca(n)) : \
rb_alloc_tmp_buffer(&(v), (n)))
rb_alloc_tmp_buffer(&(v), (n), true))
/**
* Allocates a memory region, possibly on stack. If the given size exceeds
@@ -438,30 +438,7 @@ RBIMPL_ATTR_NONNULL(())
* @return Allocated `len` bytes array.
* @post `store` holds the corresponding tmp buffer object.
*/
void *rb_alloc_tmp_buffer(volatile VALUE *store, long len);
RBIMPL_ATTR_RESTRICT()
RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((2,3))
RBIMPL_ATTR_NONNULL(())
/**
* @private
*
* This is an implementation detail of #RB_ALLOCV_N(). People don't use this
* directly.
*
* @param[out] store Pointer to a variable.
* @param[in] len Requested number of bytes to allocate.
* @param[in] count Number of elements in an array.
* @return Allocated `len` bytes array.
* @post `store` holds the corresponding tmp buffer object.
*
* @internal
*
* Although the meaning of `count` variable is clear, @shyouhei doesn't
* understand its needs.
*/
void *rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t len,size_t count);
void *rb_alloc_tmp_buffer(volatile VALUE *store, long len, bool mark);
/**
* @private
@@ -741,7 +718,7 @@ static inline void *
rb_alloc_tmp_buffer2(volatile VALUE *store, long count, size_t elsize)
{
const size_t total_size = rbimpl_size_mul_or_raise(RBIMPL_CAST((size_t)count), elsize);
return rb_alloc_tmp_buffer(store, (long)total_size);
return rb_alloc_tmp_buffer(store, (long)total_size, elsize >= sizeof(VALUE));
}
RBIMPL_SYMBOL_EXPORT_BEGIN()
+2 -2
View File
@@ -97,6 +97,7 @@ struct rb_imemo_tmpbuf_struct {
VALUE flags;
VALUE *ptr; /* malloc'ed buffer */
size_t size; /* buffer size in bytes */
bool marked; /* whether the buffer may contain object references */
};
struct rb_imemo_cdhash {
@@ -142,7 +143,6 @@ struct MEMO {
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
#endif
VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable);
VALUE rb_imemo_tmpbuf_new(void);
struct MEMO *rb_imemo_memo_new(VALUE a, VALUE b, long c);
struct MEMO *rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
@@ -212,7 +212,7 @@ rb_imemo_tmpbuf_new_from_an_RString(VALUE str)
StringValue(str);
len = RSTRING_LEN(str);
rb_alloc_tmp_buffer(&imemo, len);
rb_alloc_tmp_buffer(&imemo, len, false);
memcpy(RB_IMEMO_TMPBUF_PTR(imemo), RSTRING_PTR(str), len);
return imemo;
}
+1 -1
View File
@@ -2726,7 +2726,7 @@ open_func(void *ptr)
static void
rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
{
rb_alloc_tmp_buffer(&eargp->dup2_tmpbuf, run_exec_dup2_tmpbuf_size(len));
rb_alloc_tmp_buffer(&eargp->dup2_tmpbuf, run_exec_dup2_tmpbuf_size(len), false);
}
static VALUE