Skip to content

Commit a018cbe

Browse files
authored
Implement compaction and embedded structs (#201)
GC compaction was introduced in Ruby 2.7. Embedded Structs was introduced in Ruby 3.3. When enabled, the `struct strscanner` is stored directly inside the object slot, meaning reading the struct member doesn't require loading another memory region.
1 parent 1d85632 commit a018cbe

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

ext/strscan/extconf.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
have_func("onig_region_memsize(NULL)")
66
have_func("rb_reg_onig_match", "ruby/re.h")
77
have_func("rb_deprecate_constant")
8+
have_func("rb_gc_location", "ruby.h") # RUBY_VERSION >= 2.7
9+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
810
create_makefile 'strscan'
911
else
1012
File.write('Makefile', dummy_makefile("").join)

ext/strscan/strscan.c

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,37 +182,73 @@ extract_beg_len(struct strscanner *p, long beg_i, long len)
182182
Constructor
183183
======================================================================= */
184184

185+
#ifdef RUBY_TYPED_EMBEDDABLE
186+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
187+
#else
188+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
189+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
190+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
191+
# else
192+
# define RUBY_TYPED_EMBEDDABLE 0
193+
# endif
194+
#endif
195+
196+
#ifdef HAVE_RB_GC_LOCATION
197+
static void
198+
strscan_compact(void *ptr)
199+
{
200+
struct strscanner *p = ptr;
201+
p->str = rb_gc_location(p->str);
202+
p->regex = rb_gc_location(p->regex);
203+
}
204+
#else
205+
#define rb_gc_mark_movable rb_gc_mark
206+
#endif
207+
185208
static void
186209
strscan_mark(void *ptr)
187210
{
188211
struct strscanner *p = ptr;
189-
rb_gc_mark(p->str);
190-
rb_gc_mark(p->regex);
212+
rb_gc_mark_movable(p->str);
213+
rb_gc_mark_movable(p->regex);
191214
}
192215

193216
static void
194217
strscan_free(void *ptr)
195218
{
196219
struct strscanner *p = ptr;
197220
onig_region_free(&(p->regs), 0);
221+
#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
198222
ruby_xfree(p);
223+
#endif
199224
}
200225

201226
static size_t
202227
strscan_memsize(const void *ptr)
203228
{
204-
const struct strscanner *p = ptr;
205-
size_t size = sizeof(*p) - sizeof(p->regs);
229+
size_t size = 0;
230+
#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
231+
size += sizeof(struct strscanner);
232+
#endif
233+
206234
#ifdef HAVE_ONIG_REGION_MEMSIZE
207-
size += onig_region_memsize(&p->regs);
235+
const struct strscanner *p = ptr;
236+
size += onig_region_memsize(&p->regs) - sizeof(p->regs);
208237
#endif
209238
return size;
210239
}
211240

212241
static const rb_data_type_t strscanner_type = {
213-
"StringScanner",
214-
{strscan_mark, strscan_free, strscan_memsize},
215-
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
242+
.wrap_struct_name = "StringScanner",
243+
.function = {
244+
.dmark = strscan_mark,
245+
.dfree = strscan_free,
246+
.dsize = strscan_memsize,
247+
#ifdef HAVE_RB_GC_LOCATION
248+
.dcompact = strscan_compact,
249+
#endif
250+
},
251+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
216252
};
217253

218254
static VALUE

0 commit comments

Comments
 (0)