summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorMatt Valentine-House <matt@eightbitraptor.com>2022-04-06 09:55:23 +0100
committerAaron Patterson <aaron.patterson@gmail.com>2022-06-13 10:11:27 -0700
commit56cc3e99b6b9ec004255280337f6b8353f5e5b06 (patch)
tree2e5fd33e789155aa65a6b9329c334dff029b8349 /string.c
parentf8502a26990c652a2c3c1131614230fec446ab25 (diff)
downloadruby-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.c77
1 files changed, 73 insertions, 4 deletions
diff --git a/string.c b/string.c
index 84af905deb..4dc462f5c4 100644
--- a/string.c
+++ b/string.c
@@ -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));