summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorYukihiro Matsumoto <[email protected]>2012-06-03 07:55:39 +0900
committerYukihiro Matsumoto <[email protected]>2012-06-03 07:55:39 +0900
commit12d75223d62ed90f334980c3a15e96618250fe90 (patch)
treecd5facb0373fd3a74d457ee2289682a67ed29e55 /src
parent5fcd520514095fa9bbb31d2e7eca192b1be7dfc2 (diff)
downloadmruby-12d75223d62ed90f334980c3a15e96618250fe90.tar.gz
mruby-12d75223d62ed90f334980c3a15e96618250fe90.zip
make shared string to reference-counted C structure to reduce GC pressure
Diffstat (limited to 'src')
-rw-r--r--src/gc.c7
-rw-r--r--src/print.c2
-rw-r--r--src/string.c53
3 files changed, 29 insertions, 33 deletions
diff --git a/src/gc.c b/src/gc.c
index 04be437c1..03428765c 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -372,13 +372,6 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
break;
case MRB_TT_STRING:
- {
- struct RString *s = (struct RString*)obj;
-
- if (s->flags & MRB_STR_SHARED) {
- mrb_gc_mark(mrb, (struct RBasic*)s->aux.shared);
- }
- }
break;
case MRB_TT_RANGE:
diff --git a/src/print.c b/src/print.c
index 505597935..e6873913b 100644
--- a/src/print.c
+++ b/src/print.c
@@ -13,7 +13,7 @@ printstr(mrb_state *mrb, mrb_value obj)
{
struct RString *str;
char *s;
- size_t len;
+ int len;
if (mrb_type(obj) == MRB_TT_STRING) {
str = mrb_str_ptr(obj);
diff --git a/src/string.c b/src/string.c
index 26ed7b052..3d59948f3 100644
--- a/src/string.c
+++ b/src/string.c
@@ -49,6 +49,7 @@ str_modify(mrb_state *mrb, struct RString *s)
if (s->flags & MRB_STR_SHARED) {
char *ptr, *p;
long len;
+ struct mrb_shared_string *shared = s->aux.shared;
p = s->buf;
len = s->len;
@@ -61,6 +62,12 @@ str_modify(mrb_state *mrb, struct RString *s)
s->len = len;
s->aux.capa = len;
s->flags &= ~MRB_STR_SHARED;
+
+ shared->refcnt--;
+ if (shared->refcnt == 0) {
+ mrb_free(mrb, shared->buf);
+ mrb_free(mrb, shared);
+ }
}
}
@@ -76,9 +83,7 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, int len)
if (slen < len || slen -len > 1024) {
s->buf = mrb_realloc(mrb, s->buf, len+1);
}
- if (!(s->flags & MRB_STR_SHARED)) {
- s->aux.capa = len;
- }
+ s->aux.capa = len;
s->len = len;
s->buf[len] = '\0'; /* sentinel */
}
@@ -178,13 +183,13 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, int len)
}
if (len == 0) return;
capa = s->aux.capa;
- if (s->len >= LONG_MAX - len) {
+ if (s->len >= INT_MAX - len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string sizes too big");
}
total = s->len+len;
if (capa <= total) {
while (total > capa) {
- if (capa + 1 >= LONG_MAX / 2) {
+ if (capa + 1 >= INT_MAX / 2) {
capa = (total + 4095) / 4096;
break;
}
@@ -258,12 +263,16 @@ str_make_shared(mrb_state *mrb, mrb_value str)
str_with_class(mrb, s, str);
orig = mrb_str_ptr(str);
if (!(orig->flags & MRB_STR_SHARED)) {
- struct RString *shared = mrb_obj_alloc_string(mrb);
+ struct mrb_shared_string *shared = mrb_malloc(mrb, sizeof(struct mrb_shared_string));
- shared->buf = orig->buf;
+ shared->refcnt = 1;
+ if (orig->aux.capa > orig->len) {
+ shared->buf = mrb_realloc(mrb, shared->buf, orig->len+1);
+ }
+ else {
+ shared->buf = orig->buf;
+ }
shared->len = orig->len;
- shared->aux.capa = orig->aux.capa;
-
orig->aux.shared = shared;
orig->flags |= MRB_STR_SHARED;
}
@@ -285,16 +294,19 @@ str_make_shared(mrb_state *mrb, mrb_value str)
mrb_value
mrb_str_literal(mrb_state *mrb, mrb_value str)
{
- struct RString *orig, *s;
+ struct RString *s, *orig;
+ struct mrb_shared_string *shared;
s = str_new(mrb, 0, 0);
orig = mrb_str_ptr(str);
- while (orig->flags & MRB_STR_SHARED) {
- orig = orig->aux.shared;
+ if (!(orig->flags & MRB_STR_SHARED)) {
+ str_make_shared(mrb, str);
}
- s->buf = orig->buf;
- s->len = orig->len;
- s->aux.shared = orig;
+ shared = orig->aux.shared;
+ shared->refcnt++;
+ s->buf = shared->buf;
+ s->len = shared->len;
+ s->aux.shared = shared;
s->flags |= MRB_STR_SHARED;
return mrb_obj_value(s);
@@ -2849,19 +2861,10 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
mrb_value
mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, long len)
{
- struct RString *s = mrb_str_ptr(str);
-
if (len < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)");
}
- if (0/*STR_ASSOC_P(str)*/) {
- mrb_realloc(mrb, s->buf, s->len+len+1);
- memcpy(s->buf + s->len, ptr, len);
- s->len += len;
- s->buf[s->len] = '\0'; /* sentinel */
- return str;
- }
- str_buf_cat(mrb, s, ptr, len);
+ str_buf_cat(mrb, mrb_str_ptr(str), ptr, len);
return str;
}