revert r59359, r59356, r59355, r59354
These caused numerous CI failures I haven't been able to reproduce [ruby-core:82102] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59364 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
13155d4df5
commit
0493b1ce3a
23
hash.c
23
hash.c
@ -18,6 +18,7 @@
|
|||||||
#include "probes.h"
|
#include "probes.h"
|
||||||
#include "id.h"
|
#include "id.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
# ifdef HAVE_CRT_EXTERNS_H
|
# ifdef HAVE_CRT_EXTERNS_H
|
||||||
@ -1515,13 +1516,33 @@ hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
|
|||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
fstring_existing_str(VALUE str)
|
||||||
|
{
|
||||||
|
st_data_t fstr;
|
||||||
|
st_table *tbl = rb_vm_fstring_table();
|
||||||
|
|
||||||
|
if (st_lookup(tbl, str, &fstr)) {
|
||||||
|
if (rb_objspace_garbage_object_p(fstr)) {
|
||||||
|
return rb_fstring(str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (VALUE)fstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hash_aset_str(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
|
hash_aset_str(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
|
||||||
{
|
{
|
||||||
if (!existing && !RB_OBJ_FROZEN(*key)) {
|
if (!existing && !RB_OBJ_FROZEN(*key)) {
|
||||||
VALUE k;
|
VALUE k;
|
||||||
|
|
||||||
if ((k = rb_fstring_existing(*key)) != Qnil) {
|
if (!RB_OBJ_TAINTED(*key) &&
|
||||||
|
(k = fstring_existing_str(*key)) != Qnil) {
|
||||||
*key = k;
|
*key = k;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1590,7 +1590,6 @@ VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc,
|
|||||||
/* string.c */
|
/* string.c */
|
||||||
VALUE rb_fstring(VALUE);
|
VALUE rb_fstring(VALUE);
|
||||||
VALUE rb_fstring_new(const char *ptr, long len);
|
VALUE rb_fstring_new(const char *ptr, long len);
|
||||||
VALUE rb_fstring_existing(VALUE);
|
|
||||||
#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str))
|
#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str))
|
||||||
#define rb_fstring_literal(str) rb_fstring_lit(str)
|
#define rb_fstring_literal(str) rb_fstring_lit(str)
|
||||||
VALUE rb_fstring_cstr(const char *str);
|
VALUE rb_fstring_cstr(const char *str);
|
||||||
@ -1743,7 +1742,7 @@ void rb_vm_check_redefinition_by_prepend(VALUE klass);
|
|||||||
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
|
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
|
||||||
VALUE ruby_vm_special_exception_copy(VALUE);
|
VALUE ruby_vm_special_exception_copy(VALUE);
|
||||||
PUREFUNC(st_table *rb_vm_fstring_table(void));
|
PUREFUNC(st_table *rb_vm_fstring_table(void));
|
||||||
PUREFUNC(st_table *rb_vm_tfstring_table(void));
|
|
||||||
|
|
||||||
/* vm_dump.c */
|
/* vm_dump.c */
|
||||||
void rb_print_backtrace(void);
|
void rb_print_backtrace(void);
|
||||||
|
20
st.c
20
st.c
@ -2092,23 +2092,6 @@ st_rehash(st_table *tab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RUBY
|
#ifdef RUBY
|
||||||
|
|
||||||
static VALUE
|
|
||||||
str_key(VALUE key)
|
|
||||||
{
|
|
||||||
VALUE k;
|
|
||||||
|
|
||||||
if (RB_OBJ_FROZEN(key)) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
if ((k = rb_fstring_existing(key)) != Qnil) {
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return rb_str_new_frozen(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mimics ruby's { foo => bar } syntax. This function is placed here
|
/* Mimics ruby's { foo => bar } syntax. This function is placed here
|
||||||
because it touches table internals and write barriers at once. */
|
because it touches table internals and write barriers at once. */
|
||||||
void
|
void
|
||||||
@ -2131,7 +2114,8 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
|
|||||||
for (i = 0; i < argc; /* */) {
|
for (i = 0; i < argc; /* */) {
|
||||||
VALUE key = argv[i++];
|
VALUE key = argv[i++];
|
||||||
VALUE val = argv[i++];
|
VALUE val = argv[i++];
|
||||||
st_data_t k = (rb_obj_class(key) == rb_cString) ? str_key(key) : key;
|
st_data_t k = (rb_obj_class(key) == rb_cString) ?
|
||||||
|
rb_str_new_frozen(key) : key;
|
||||||
st_table_entry e;
|
st_table_entry e;
|
||||||
e.hash = do_hash(k, tab);
|
e.hash = do_hash(k, tab);
|
||||||
e.key = k;
|
e.key = k;
|
||||||
|
118
string.c
118
string.c
@ -301,79 +301,27 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
tainted_fstr_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
|
|
||||||
{
|
|
||||||
VALUE *fstr = (VALUE *)arg;
|
|
||||||
VALUE str = (VALUE)*key;
|
|
||||||
|
|
||||||
if (existing) {
|
|
||||||
/* because of lazy sweep, str may be unmarked already and swept
|
|
||||||
* at next time */
|
|
||||||
if (rb_objspace_garbage_object_p(str)) {
|
|
||||||
*fstr = Qundef;
|
|
||||||
return ST_DELETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*fstr = str;
|
|
||||||
return ST_STOP;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
str = rb_str_resurrect(str);
|
|
||||||
RB_OBJ_TAINT_RAW(str);
|
|
||||||
RB_FL_SET_RAW(str, RSTRING_FSTR);
|
|
||||||
RB_OBJ_FREEZE_RAW(str);
|
|
||||||
|
|
||||||
*key = *val = *fstr = str;
|
|
||||||
return ST_CONTINUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
register_fstring_tainted(VALUE str, st_table *tfstrings)
|
|
||||||
{
|
|
||||||
st_data_t fstr;
|
|
||||||
|
|
||||||
do {
|
|
||||||
fstr = (st_data_t)str;
|
|
||||||
st_update(tfstrings, fstr, tainted_fstr_update, (st_data_t)&fstr);
|
|
||||||
} while ((VALUE)fstr == Qundef);
|
|
||||||
|
|
||||||
str = (VALUE)fstr;
|
|
||||||
assert(OBJ_FROZEN_RAW(str));
|
|
||||||
assert(!FL_TEST_RAW(str, STR_FAKESTR));
|
|
||||||
assert(!FL_TEST_RAW(str, FL_EXIVAR));
|
|
||||||
assert(FL_TEST_RAW(str, RSTRING_FSTR));
|
|
||||||
assert(FL_TEST_RAW(str, FL_TAINT));
|
|
||||||
assert(RBASIC_CLASS(str) == rb_cString);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
RUBY_FUNC_EXPORTED
|
RUBY_FUNC_EXPORTED
|
||||||
VALUE
|
VALUE
|
||||||
rb_fstring(VALUE str)
|
rb_fstring(VALUE str)
|
||||||
{
|
{
|
||||||
VALUE fstr;
|
VALUE fstr;
|
||||||
int bare_ish;
|
int bare;
|
||||||
|
|
||||||
Check_Type(str, T_STRING);
|
Check_Type(str, T_STRING);
|
||||||
|
|
||||||
if (FL_TEST(str, RSTRING_FSTR))
|
if (FL_TEST(str, RSTRING_FSTR))
|
||||||
return str;
|
return str;
|
||||||
|
|
||||||
bare_ish = !FL_TEST_RAW(str, FL_EXIVAR) && RBASIC_CLASS(str) == rb_cString;
|
bare = BARE_STRING_P(str);
|
||||||
if (STR_EMBED_P(str) && !bare_ish) {
|
if (STR_EMBED_P(str) && !bare) {
|
||||||
OBJ_FREEZE_RAW(str);
|
OBJ_FREEZE_RAW(str);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
if (!FL_TEST_RAW(str, FL_TAINT)) {
|
|
||||||
fstr = register_fstring(str);
|
fstr = register_fstring(str);
|
||||||
}
|
|
||||||
else {
|
if (!bare) {
|
||||||
fstr = register_fstring_tainted(str, rb_vm_tfstring_table());
|
|
||||||
}
|
|
||||||
if (!bare_ish) {
|
|
||||||
str_replace_shared_without_enc(str, fstr);
|
str_replace_shared_without_enc(str, fstr);
|
||||||
OBJ_FREEZE_RAW(str);
|
OBJ_FREEZE_RAW(str);
|
||||||
return str;
|
return str;
|
||||||
@ -401,59 +349,6 @@ register_fstring(VALUE str)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_fstring_existing0(VALUE str)
|
|
||||||
{
|
|
||||||
st_table *frozen_strings = rb_vm_fstring_table();
|
|
||||||
st_data_t fstr;
|
|
||||||
|
|
||||||
if (st_lookup(frozen_strings, str, &fstr)) {
|
|
||||||
if (rb_objspace_garbage_object_p(fstr)) {
|
|
||||||
return register_fstring(str);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (VALUE)fstr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Qnil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_tainted_fstring_existing(VALUE str)
|
|
||||||
{
|
|
||||||
VALUE ret;
|
|
||||||
st_data_t fstr;
|
|
||||||
st_table *tfstrings = rb_vm_tfstring_table();
|
|
||||||
|
|
||||||
if (st_lookup(tfstrings, str, &fstr)) {
|
|
||||||
ret = (VALUE)fstr;
|
|
||||||
if (!rb_objspace_garbage_object_p(ret)) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = rb_fstring_existing0(str);
|
|
||||||
if (NIL_P(ret)) {
|
|
||||||
return Qnil;
|
|
||||||
}
|
|
||||||
if (!RB_FL_TEST_RAW(ret, RSTRING_FSTR)) {
|
|
||||||
return Qnil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return register_fstring_tainted(str, tfstrings);
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
|
||||||
rb_fstring_existing(VALUE str)
|
|
||||||
{
|
|
||||||
if (FL_TEST_RAW(str, RSTRING_FSTR))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (!RB_OBJ_TAINTED_RAW(str))
|
|
||||||
return rb_fstring_existing0(str);
|
|
||||||
|
|
||||||
return rb_tainted_fstring_existing(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
|
setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
|
||||||
{
|
{
|
||||||
@ -1416,7 +1311,6 @@ rb_str_free(VALUE str)
|
|||||||
if (FL_TEST(str, RSTRING_FSTR)) {
|
if (FL_TEST(str, RSTRING_FSTR)) {
|
||||||
st_data_t fstr = (st_data_t)str;
|
st_data_t fstr = (st_data_t)str;
|
||||||
st_delete(rb_vm_fstring_table(), &fstr, NULL);
|
st_delete(rb_vm_fstring_table(), &fstr, NULL);
|
||||||
st_delete(rb_vm_tfstring_table(), &fstr, NULL);
|
|
||||||
RB_DEBUG_COUNTER_INC(obj_str_fstr);
|
RB_DEBUG_COUNTER_INC(obj_str_fstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,44 +181,6 @@ class TestRubyOptimization < Test::Unit::TestCase
|
|||||||
assert_redefine_method('Hash', 'empty?', 'assert_nil({}.empty?); assert_nil({1=>1}.empty?)')
|
assert_redefine_method('Hash', 'empty?', 'assert_nil({}.empty?); assert_nil({1=>1}.empty?)')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hash_reuse_fstring
|
|
||||||
embed = -'h e l l o'
|
|
||||||
shared = -'this string is too long to be embedded and should be shared'
|
|
||||||
assert_not_equal GC::INTERNAL_CONSTANTS[:RVALUE_SIZE],
|
|
||||||
ObjectSpace.memsize_of(shared),
|
|
||||||
'update this test if string embedding changed'
|
|
||||||
|
|
||||||
[ embed, shared ].each do |exp|
|
|
||||||
key = exp.split(' ').join(' ')
|
|
||||||
h = {}
|
|
||||||
h[key] = true
|
|
||||||
assert_not_same key, h.keys[0]
|
|
||||||
assert_predicate h.keys[0], :frozen?
|
|
||||||
assert_same exp, h.keys[0]
|
|
||||||
|
|
||||||
h = { key => 1 }
|
|
||||||
assert_same exp, h.keys[0], 'newhash insn should reuse strings, too'
|
|
||||||
|
|
||||||
h1 = {}
|
|
||||||
h2 = {}
|
|
||||||
key.taint
|
|
||||||
h1[key] = true
|
|
||||||
h2[key] = true
|
|
||||||
k1 = h1.keys[0]
|
|
||||||
k2 = h2.keys[0]
|
|
||||||
assert_same k1, k2
|
|
||||||
assert_predicate k1, :tainted?
|
|
||||||
|
|
||||||
h = { key => 1 }
|
|
||||||
assert_not_predicate key, :frozen?
|
|
||||||
assert_same k1, h.keys[0], 'newhash insn should reuse tainted strings'
|
|
||||||
|
|
||||||
assert_equal GC::INTERNAL_CONSTANTS[:RVALUE_SIZE],
|
|
||||||
ObjectSpace.memsize_of(k1),
|
|
||||||
'tainted string should share with untainted fstring'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_hash_aref_with
|
def test_hash_aref_with
|
||||||
h = { "foo" => 1 }
|
h = { "foo" => 1 }
|
||||||
assert_equal 1, h["foo"]
|
assert_equal 1, h["foo"]
|
||||||
|
@ -2750,14 +2750,8 @@ CODE
|
|||||||
assert_not_same(str, +str)
|
assert_not_same(str, +str)
|
||||||
assert_same(str, -str)
|
assert_same(str, -str)
|
||||||
|
|
||||||
return unless @cls == String
|
|
||||||
bar = %w(b a r).join('')
|
bar = %w(b a r).join('')
|
||||||
assert_not_predicate bar, :tainted?
|
|
||||||
assert_not_predicate str, :tainted?
|
|
||||||
assert_same(str, -bar, "uminus deduplicates [Feature #13077]")
|
assert_same(str, -bar, "uminus deduplicates [Feature #13077]")
|
||||||
bar = %w(b a r).taint.join('')
|
|
||||||
tstr = str.dup.taint
|
|
||||||
assert_same -tstr, -bar
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ord
|
def test_ord
|
||||||
|
12
vm.c
12
vm.c
@ -2206,10 +2206,6 @@ ruby_vm_destruct(rb_vm_t *vm)
|
|||||||
st_free_table(vm->frozen_strings);
|
st_free_table(vm->frozen_strings);
|
||||||
vm->frozen_strings = 0;
|
vm->frozen_strings = 0;
|
||||||
}
|
}
|
||||||
if (vm->tainted_frozen_strings) {
|
|
||||||
st_free_table(vm->tainted_frozen_strings);
|
|
||||||
vm->tainted_frozen_strings = 0;
|
|
||||||
}
|
|
||||||
rb_vm_gvl_destroy(vm);
|
rb_vm_gvl_destroy(vm);
|
||||||
if (objspace) {
|
if (objspace) {
|
||||||
rb_objspace_free(objspace);
|
rb_objspace_free(objspace);
|
||||||
@ -3146,8 +3142,6 @@ Init_vm_objects(void)
|
|||||||
vm->mark_object_ary = rb_ary_tmp_new(128);
|
vm->mark_object_ary = rb_ary_tmp_new(128);
|
||||||
vm->loading_table = st_init_strtable();
|
vm->loading_table = st_init_strtable();
|
||||||
vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 1000);
|
vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 1000);
|
||||||
vm->tainted_frozen_strings =
|
|
||||||
st_init_table_with_size(&rb_fstring_hash_type, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* top self */
|
/* top self */
|
||||||
@ -3209,12 +3203,6 @@ rb_vm_fstring_table(void)
|
|||||||
return GET_VM()->frozen_strings;
|
return GET_VM()->frozen_strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
st_table *
|
|
||||||
rb_vm_tfstring_table(void)
|
|
||||||
{
|
|
||||||
return GET_VM()->tainted_frozen_strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if VM_COLLECT_USAGE_DETAILS
|
#if VM_COLLECT_USAGE_DETAILS
|
||||||
|
|
||||||
#define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
|
#define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user