Project

General

Profile

Bug #13085 ยป 0001-io.c-recycle-garbage-on-write.patch

normalperson (Eric Wong), 01/28/2017 08:50 AM

View differences:

internal.h
1459 1459
char *rb_str_fill_terminator(VALUE str, const int termlen);
1460 1460
void rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen);
1461 1461
VALUE rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg);
1462
VALUE rb_str_tmp_frozen_acquire(VALUE str);
1463
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp);
1462 1464
VALUE rb_str_chomp_string(VALUE str, VALUE chomp);
1463 1465
#ifdef RUBY_ENCODING_H
1464 1466
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc);
io.c
1419 1419
    return str;
1420 1420
}
1421 1421

  
1422
struct fwrite_arg {
1423
    VALUE orig;
1424
    VALUE tmp;
1425
    rb_io_t *fptr;
1426
    int nosync;
1427
};
1428

  
1429
static VALUE
1430
fwrite_do(VALUE arg)
1431
{
1432
    struct fwrite_arg *fa = (struct fwrite_arg *)arg;
1433
    const char *ptr;
1434
    long len;
1435

  
1436
    RSTRING_GETMEM(fa->tmp, ptr, len);
1437

  
1438
    return (VALUE)io_binwrite(fa->tmp, ptr, len, fa->fptr, fa->nosync);
1439
}
1440

  
1441
static VALUE
1442
fwrite_end(VALUE arg)
1443
{
1444
    struct fwrite_arg *fa = (struct fwrite_arg *)arg;
1445

  
1446
    rb_str_tmp_frozen_release(fa->orig, fa->tmp);
1447

  
1448
    return Qfalse;
1449
}
1450

  
1422 1451
static long
1423 1452
io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1424 1453
{
1425 1454
    int converted = 0;
1455
    struct fwrite_arg fa;
1426 1456
#ifdef _WIN32
1427 1457
    if (fptr->mode & FMODE_TTY) {
1428 1458
	long len = rb_w32_write_console(str, fptr->fd);
......
1432 1462
    str = do_writeconv(str, fptr, &converted);
1433 1463
    if (converted)
1434 1464
	OBJ_FREEZE(str);
1435
    else
1436
	str = rb_str_new_frozen(str);
1437 1465

  
1438
    return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
1439
		       fptr, nosync);
1466
    fa.orig = str;
1467
    fa.tmp = rb_str_tmp_frozen_acquire(str);
1468
    fa.fptr = fptr;
1469
    fa.nosync = nosync;
1470

  
1471
    return (long)rb_ensure(fwrite_do, (VALUE)&fa, fwrite_end, (VALUE)&fa);
1440 1472
}
1441 1473

  
1442 1474
ssize_t
string.c
70 70
 * 1:     RSTRING_NOEMBED
71 71
 * 2:     STR_SHARED (== ELTS_SHARED)
72 72
 * 2-6:   RSTRING_EMBED_LEN (5 bits == 32)
73
 * 6:     STR_IS_SHARED_M (shared, when RSTRING_NOEMBED==1 && klass==0)
73 74
 * 7:     STR_TMPLOCK
74 75
 * 8-9:   ENC_CODERANGE (2 bits)
75 76
 * 10-16: ENCODING (7 bits == 128)
......
79 80
 */
80 81

  
81 82
#define RUBY_MAX_CHAR_LEN 16
83
#define STR_IS_SHARED_M FL_USER6
82 84
#define STR_TMPLOCK FL_USER7
83 85
#define STR_NOFREE FL_USER18
84 86
#define STR_FAKESTR FL_USER19
......
150 152
    if (!FL_TEST(str, STR_FAKESTR)) { \
151 153
	RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
152 154
	FL_SET((str), STR_SHARED); \
155
	if (RBASIC_CLASS((shared_str)) == 0) /* for CoW-friendliness */ \
156
	    FL_SET_RAW((shared_str), STR_IS_SHARED_M); \
153 157
    } \
154 158
} while (0)
155 159

  
......
1127 1131
    return str;
1128 1132
}
1129 1133

  
1134
VALUE
1135
rb_str_tmp_frozen_acquire(VALUE orig)
1136
{
1137
    VALUE tmp;
1138

  
1139
    if (OBJ_FROZEN_RAW(orig)) return orig;
1140

  
1141
    tmp = str_new_frozen(0, orig);
1142
    OBJ_INFECT(tmp, orig);
1143

  
1144
    return tmp;
1145
}
1146

  
1147
void
1148
rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
1149
{
1150
    if (RBASIC_CLASS(tmp) != 0)
1151
	return;
1152

  
1153
    if (FL_TEST_RAW(orig, STR_SHARED) &&
1154
	    !FL_TEST_RAW(orig, STR_TMPLOCK|RUBY_FL_FREEZE)) {
1155
	VALUE shared = RSTRING(orig)->as.heap.aux.shared;
1156

  
1157
	if (shared == tmp && !FL_TEST_RAW(tmp, STR_IS_SHARED_M)) {
1158
	    FL_UNSET_RAW(orig, STR_SHARED);
1159
	    assert(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
1160
	    assert(RSTRING(orig)->as.heap.len == RSTRING(tmp)->as.heap.len);
1161
	    RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa;
1162
	    RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
1163
	    assert(OBJ_FROZEN_RAW(tmp));
1164
	    rb_gc_force_recycle(tmp);
1165
	}
1166
    }
1167
    else if (STR_EMBED_P(tmp)) {
1168
	assert(OBJ_FROZEN_RAW(tmp));
1169
	rb_gc_force_recycle(tmp);
1170
    }
1171
}
1172

  
1130 1173
static VALUE
1131 1174
str_new_frozen(VALUE klass, VALUE orig)
1132 1175
{
......
1152 1195
		RSTRING(str)->as.heap.len -= ofs + rest;
1153 1196
	    }
1154 1197
	    else {
1198
		if (RBASIC_CLASS(shared) == 0)
1199
		    FL_SET_RAW(shared, STR_IS_SHARED_M);
1155 1200
		return shared;
1156 1201
	    }
1157 1202
	}
......
1171 1216
	    RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
1172 1217
	    RBASIC(orig)->flags &= ~STR_NOFREE;
1173 1218
	    STR_SET_SHARED(orig, str);
1219
	    if (klass == 0)
1220
		FL_UNSET_RAW(str, STR_IS_SHARED_M);
1174 1221
	}
1175 1222
    }
1176 1223

  
1177
-