diff options
author | Matt Valentine-House <matt@eightbitraptor.com> | 2022-04-06 09:55:23 +0100 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2022-06-13 10:11:27 -0700 |
commit | 56cc3e99b6b9ec004255280337f6b8353f5e5b06 (patch) | |
tree | 2e5fd33e789155aa65a6b9329c334dff029b8349 /string.c | |
parent | f8502a26990c652a2c3c1131614230fec446ab25 (diff) | |
download | ruby-56cc3e99b6b9ec004255280337f6b8353f5e5b06.tar.gz |
Move String RVALUES between pools
And re-embed any strings that can now fit inside the slot they've been
moved to
Diffstat (limited to 'string.c')
-rw-r--r-- | string.c | 77 |
1 files changed, 73 insertions, 4 deletions
@@ -221,17 +221,51 @@ str_embed_capa(VALUE str) #endif } +bool +rb_str_reembeddable_p(VALUE str) +{ + return !FL_TEST(str, STR_NOFREE|STR_SHARED_ROOT|STR_SHARED); +} + static inline size_t -str_embed_size(long capa) +rb_str_embed_size(long capa) { return offsetof(struct RString, as.embed.ary) + capa; } +bool +rb_str_shared_root_p(VALUE str) +{ + return FL_TEST_RAW(str, STR_SHARED_ROOT); +} + +size_t +rb_str_size_as_embedded(VALUE str) +{ + size_t real_size; +#if USE_RVARGC + if (STR_EMBED_P(str)) { + real_size = rb_str_embed_size(RSTRING(str)->as.embed.len) + TERM_LEN(str); + } + /* if the string is not currently embedded, but it can be embedded, how + * much space would it require */ + else if (rb_str_reembeddable_p(str)) { + real_size = rb_str_embed_size(RSTRING(str)->as.heap.len) + TERM_LEN(str); + } + else { +#endif + real_size = sizeof(struct RString); +#if USE_RVARGC + } +#endif + return real_size; +} + static inline bool STR_EMBEDDABLE_P(long len, long termlen) { #if USE_RVARGC - return rb_gc_size_allocatable_p(str_embed_size(len + termlen)); + return rb_gc_size_allocatable_p(rb_str_embed_size(len + termlen)); #else return len <= RSTRING_EMBED_LEN_MAX + 1 - termlen; #endif @@ -265,6 +299,41 @@ rb_str_make_independent(VALUE str) } void +rb_str_make_embedded(VALUE str) { + RUBY_ASSERT(rb_str_reembeddable_p(str)); + RUBY_ASSERT(!STR_EMBED_P(str)); + + char *buf = RSTRING_PTR(str); + long len = RSTRING_LEN(str); + + STR_SET_EMBED(str); + STR_SET_EMBED_LEN(str, len); + + memmove(RSTRING_PTR(str), buf, len); + ruby_xfree(buf); +} + +void +rb_str_update_shared_ary(VALUE str, VALUE old_root, VALUE new_root) +{ + // if the root location hasn't changed, we don't need to update + if (new_root == old_root) { + return; + } + + // if the root string isn't embedded, we don't need to touch the ponter. + // it already points to the shame shared buffer + if (!STR_EMBED_P(new_root)) { + return; + } + + size_t offset = (size_t)((uintptr_t)RSTRING(str)->as.heap.ptr - (uintptr_t)RSTRING(old_root)->as.embed.ary); + + RUBY_ASSERT(RSTRING(str)->as.heap.ptr >= RSTRING(old_root)->as.embed.ary); + RSTRING(str)->as.heap.ptr = RSTRING(new_root)->as.embed.ary + offset; +} + +void rb_debug_rstring_null_ptr(const char *func) { fprintf(stderr, "%s is returning NULL!! " @@ -849,7 +918,7 @@ str_alloc(VALUE klass, size_t size) static inline VALUE str_alloc_embed(VALUE klass, size_t capa) { - size_t size = str_embed_size(capa); + size_t size = rb_str_embed_size(capa); assert(rb_gc_size_allocatable_p(size)); #if !USE_RVARGC assert(size <= sizeof(struct RString)); @@ -1693,7 +1762,7 @@ ec_str_alloc(struct rb_execution_context_struct *ec, VALUE klass, size_t size) static inline VALUE ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa) { - size_t size = str_embed_size(capa); + size_t size = rb_str_embed_size(capa); assert(rb_gc_size_allocatable_p(size)); #if !USE_RVARGC assert(size <= sizeof(struct RString)); |