mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
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:
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
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user