fixed encoding table
This reduces global lock acquiring for reading. https://bugs.ruby-lang.org/issues/18949
This commit is contained in:
parent
15b60bb1a4
commit
ae19ac5b5b
Notes:
git
2022-12-16 01:04:55 +00:00
2
NEWS.md
2
NEWS.md
@ -202,6 +202,8 @@ Note: We're only listing outstanding class updates.
|
||||
try to dynamically guess the endian based on a byte order mark.
|
||||
Use `Encoding::UTF_16BE`/`UTF_16LE` and `Encoding::UTF_32BE`/`UTF_32LE` instead.
|
||||
This change speeds up getting the encoding of a String. [[Feature #18949]]
|
||||
* Limit maximum encoding set size by 256.
|
||||
If exceeding maximum size, `EncodingError` will be raised. [[Feature #18949]]
|
||||
|
||||
* Enumerator
|
||||
|
||||
|
@ -1474,7 +1474,7 @@ assert_equal "#{N}#{N}", %Q{
|
||||
}
|
||||
|
||||
# enc_table
|
||||
assert_equal "#{N/10}", %Q{
|
||||
assert_equal "100", %Q{
|
||||
Ractor.new do
|
||||
loop do
|
||||
Encoding.find("test-enc-#{rand(5_000)}").inspect
|
||||
@ -1483,7 +1483,7 @@ assert_equal "#{N/10}", %Q{
|
||||
end
|
||||
|
||||
src = Encoding.find("UTF-8")
|
||||
#{N/10}.times{|i|
|
||||
100.times{|i|
|
||||
src.replicate("test-enc-\#{i}")
|
||||
}
|
||||
}
|
||||
|
154
encoding.c
154
encoding.c
@ -56,9 +56,8 @@ int rb_encdb_alias(const char *alias, const char *orig);
|
||||
static ID id_encoding;
|
||||
VALUE rb_cEncoding;
|
||||
|
||||
#define DEFAULT_ENCODING_LIST_CAPA 128
|
||||
static VALUE rb_default_encoding_list;
|
||||
static VALUE rb_additional_encoding_list;
|
||||
#define ENCODING_LIST_CAPA 256
|
||||
static VALUE rb_encoding_list;
|
||||
|
||||
struct rb_encoding_entry {
|
||||
const char *name;
|
||||
@ -67,9 +66,8 @@ struct rb_encoding_entry {
|
||||
};
|
||||
|
||||
static struct enc_table {
|
||||
struct rb_encoding_entry *list;
|
||||
struct rb_encoding_entry list[ENCODING_LIST_CAPA];
|
||||
int count;
|
||||
int size;
|
||||
st_table *names;
|
||||
} global_enc_table;
|
||||
|
||||
@ -128,47 +126,25 @@ enc_new(rb_encoding *encoding)
|
||||
static void
|
||||
enc_list_update(int index, rb_raw_encoding *encoding)
|
||||
{
|
||||
if (index < DEFAULT_ENCODING_LIST_CAPA) {
|
||||
VALUE list = rb_default_encoding_list;
|
||||
if (list && NIL_P(rb_ary_entry(list, index))) {
|
||||
/* initialize encoding data */
|
||||
rb_ary_store(list, index, enc_new(encoding));
|
||||
}
|
||||
}
|
||||
else {
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
VALUE list = rb_additional_encoding_list;
|
||||
if (list && NIL_P(rb_ary_entry(list, index))) {
|
||||
/* initialize encoding data */
|
||||
rb_ary_store(list, index - DEFAULT_ENCODING_LIST_CAPA, enc_new(encoding));
|
||||
}
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
RUBY_ASSERT(index < ENCODING_LIST_CAPA);
|
||||
|
||||
VALUE list = rb_encoding_list;
|
||||
if (list && NIL_P(rb_ary_entry(list, index))) {
|
||||
/* initialize encoding data */
|
||||
rb_ary_store(list, index, enc_new(encoding));
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
enc_list_lookup(int idx)
|
||||
{
|
||||
VALUE list, enc;
|
||||
VALUE list, enc = Qnil;
|
||||
|
||||
if (idx < DEFAULT_ENCODING_LIST_CAPA) {
|
||||
if (!(list = rb_default_encoding_list)) {
|
||||
rb_bug("rb_enc_from_encoding_index(%d): no rb_default_encoding_list", idx);
|
||||
}
|
||||
if (idx < ENCODING_LIST_CAPA) {
|
||||
list = rb_encoding_list;
|
||||
RUBY_ASSERT(list);
|
||||
enc = rb_ary_entry(list, idx);
|
||||
}
|
||||
else {
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
if (!(list = rb_additional_encoding_list)) {
|
||||
rb_bug("rb_enc_from_encoding_index(%d): no rb_additional_encoding_list", idx);
|
||||
}
|
||||
enc = rb_ary_entry(list, idx - DEFAULT_ENCODING_LIST_CAPA);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
}
|
||||
|
||||
if (NIL_P(enc)) {
|
||||
rb_bug("rb_enc_from_encoding_index(%d): not created yet", idx);
|
||||
@ -345,16 +321,10 @@ rb_find_encoding(VALUE enc)
|
||||
static int
|
||||
enc_table_expand(struct enc_table *enc_table, int newsize)
|
||||
{
|
||||
struct rb_encoding_entry *ent;
|
||||
int count = newsize;
|
||||
|
||||
if (enc_table->size >= newsize) return newsize;
|
||||
newsize = (newsize + 7) / 8 * 8;
|
||||
ent = REALLOC_N(enc_table->list, struct rb_encoding_entry, newsize);
|
||||
memset(ent + enc_table->size, 0, sizeof(*ent)*(newsize - enc_table->size));
|
||||
enc_table->list = ent;
|
||||
enc_table->size = newsize;
|
||||
return count;
|
||||
if (newsize > ENCODING_LIST_CAPA) {
|
||||
rb_raise(rb_eEncodingError, "too many encoding (> %d)", ENCODING_LIST_CAPA);
|
||||
}
|
||||
return newsize;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -413,17 +383,7 @@ enc_from_index(struct enc_table *enc_table, int index)
|
||||
rb_encoding *
|
||||
rb_enc_from_index(int index)
|
||||
{
|
||||
rb_encoding *enc;
|
||||
|
||||
switch (index) {
|
||||
case ENCINDEX_ASCII_8BIT: return global_enc_ascii;
|
||||
case ENCINDEX_UTF_8: return global_enc_utf_8;
|
||||
case ENCINDEX_US_ASCII: return global_enc_us_ascii;
|
||||
default:
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table,
|
||||
enc = enc_from_index(enc_table, index));
|
||||
return enc;
|
||||
}
|
||||
return enc_from_index(&global_enc_table, index);
|
||||
}
|
||||
|
||||
int
|
||||
@ -484,11 +444,14 @@ rb_encdb_declare(const char *name)
|
||||
}
|
||||
|
||||
static void
|
||||
enc_check_duplication(struct enc_table *enc_table, const char *name)
|
||||
enc_check_addable(struct enc_table *enc_table, const char *name)
|
||||
{
|
||||
if (enc_registered(enc_table, name) >= 0) {
|
||||
rb_raise(rb_eArgError, "encoding %s is already registered", name);
|
||||
}
|
||||
else if (!valid_encoding_name_p(name)) {
|
||||
rb_raise(rb_eArgError, "invalid encoding name: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
static rb_encoding*
|
||||
@ -524,11 +487,7 @@ rb_enc_set_base(const char *name, const char *orig)
|
||||
int
|
||||
rb_enc_set_dummy(int index)
|
||||
{
|
||||
rb_encoding *enc;
|
||||
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table,
|
||||
enc = enc_table->list[index].enc);
|
||||
|
||||
rb_encoding *enc = global_enc_table.list[index].enc;
|
||||
ENC_SET_DUMMY((rb_raw_encoding *)enc);
|
||||
return index;
|
||||
}
|
||||
@ -538,7 +497,7 @@ enc_replicate(struct enc_table *enc_table, const char *name, rb_encoding *encodi
|
||||
{
|
||||
int idx;
|
||||
|
||||
enc_check_duplication(enc_table, name);
|
||||
enc_check_addable(enc_table, name);
|
||||
idx = enc_register(enc_table, name, encoding);
|
||||
if (idx < 0) rb_raise(rb_eArgError, "invalid encoding name: %s", name);
|
||||
set_base_encoding(enc_table, idx, encoding);
|
||||
@ -727,7 +686,7 @@ rb_enc_alias(const char *alias, const char *orig)
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
enc_check_duplication(enc_table, alias);
|
||||
enc_check_addable(enc_table, alias);
|
||||
if ((idx = rb_enc_find_index(orig)) < 0) {
|
||||
r = -1;
|
||||
}
|
||||
@ -764,7 +723,7 @@ rb_enc_init(struct enc_table *enc_table)
|
||||
{
|
||||
enc_table_expand(enc_table, ENCODING_COUNT + 1);
|
||||
if (!enc_table->names) {
|
||||
enc_table->names = st_init_strcasetable();
|
||||
enc_table->names = st_init_strcasetable_with_size(ENCODING_LIST_CAPA);
|
||||
}
|
||||
#define OnigEncodingASCII_8BIT OnigEncodingASCII
|
||||
#define ENC_REGISTER(enc) enc_register_at(enc_table, ENCINDEX_##enc, rb_enc_name(&OnigEncoding##enc), &OnigEncoding##enc)
|
||||
@ -877,11 +836,9 @@ rb_enc_autoload(rb_encoding *enc)
|
||||
int
|
||||
rb_enc_find_index(const char *name)
|
||||
{
|
||||
int i;
|
||||
int i = enc_registered(&global_enc_table, name);
|
||||
rb_encoding *enc;
|
||||
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table, i = enc_registered(enc_table, name));
|
||||
|
||||
if (i < 0) {
|
||||
i = load_encoding(name);
|
||||
}
|
||||
@ -1368,10 +1325,7 @@ enc_names(VALUE self)
|
||||
|
||||
args[0] = (VALUE)rb_to_encoding_index(self);
|
||||
args[1] = rb_ary_new2(0);
|
||||
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table,
|
||||
st_foreach(enc_table->names, enc_names_i, (st_data_t)args));
|
||||
|
||||
st_foreach(global_enc_table.names, enc_names_i, (st_data_t)args);
|
||||
return args[1];
|
||||
}
|
||||
|
||||
@ -1397,14 +1351,7 @@ static VALUE
|
||||
enc_list(VALUE klass)
|
||||
{
|
||||
VALUE ary = rb_ary_new2(0);
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
rb_ary_replace(ary, rb_default_encoding_list);
|
||||
rb_ary_concat(ary, rb_additional_encoding_list);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
rb_ary_replace(ary, rb_encoding_list);
|
||||
return ary;
|
||||
}
|
||||
|
||||
@ -1553,15 +1500,17 @@ rb_locale_encindex(void)
|
||||
|
||||
if (idx < 0) idx = ENCINDEX_UTF_8;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
if (enc_registered(enc_table, "locale") < 0) {
|
||||
if (enc_registered(&global_enc_table, "locale") < 0) {
|
||||
# if defined _WIN32
|
||||
void Init_w32_codepage(void);
|
||||
Init_w32_codepage();
|
||||
# endif
|
||||
enc_alias_internal(enc_table, "locale", idx);
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
enc_alias_internal(enc_table, "locale", idx);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return idx;
|
||||
}
|
||||
@ -1575,13 +1524,8 @@ rb_locale_encoding(void)
|
||||
int
|
||||
rb_filesystem_encindex(void)
|
||||
{
|
||||
int idx;
|
||||
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table,
|
||||
idx = enc_registered(enc_table, "filesystem"));
|
||||
|
||||
if (idx < 0)
|
||||
idx = ENCINDEX_ASCII_8BIT;
|
||||
int idx = enc_registered(&global_enc_table, "filesystem");
|
||||
if (idx < 0) idx = ENCINDEX_ASCII_8BIT;
|
||||
return idx;
|
||||
}
|
||||
|
||||
@ -1872,15 +1816,8 @@ rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
|
||||
static VALUE
|
||||
rb_enc_name_list(VALUE klass)
|
||||
{
|
||||
VALUE ary;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
ary = rb_ary_new2(enc_table->names->num_entries);
|
||||
st_foreach(enc_table->names, rb_enc_name_list_i, (st_data_t)ary);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
VALUE ary = rb_ary_new2(global_enc_table.names->num_entries);
|
||||
st_foreach(global_enc_table.names, rb_enc_name_list_i, (st_data_t)ary);
|
||||
return ary;
|
||||
}
|
||||
|
||||
@ -1926,8 +1863,7 @@ rb_enc_aliases(VALUE klass)
|
||||
aliases[0] = rb_hash_new();
|
||||
aliases[1] = rb_ary_new();
|
||||
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table,
|
||||
st_foreach(enc_table->names, rb_enc_aliases_enc_i, (st_data_t)aliases));
|
||||
st_foreach(global_enc_table.names, rb_enc_aliases_enc_i, (st_data_t)aliases);
|
||||
|
||||
return aliases[0];
|
||||
}
|
||||
@ -1996,13 +1932,7 @@ Init_Encoding(void)
|
||||
|
||||
struct enc_table *enc_table = &global_enc_table;
|
||||
|
||||
if (DEFAULT_ENCODING_LIST_CAPA < enc_table->count) rb_bug("DEFAULT_ENCODING_LIST_CAPA is too small");
|
||||
|
||||
list = rb_additional_encoding_list = rb_ary_new();
|
||||
RBASIC_CLEAR_CLASS(list);
|
||||
rb_gc_register_mark_object(list);
|
||||
|
||||
list = rb_default_encoding_list = rb_ary_new2(DEFAULT_ENCODING_LIST_CAPA);
|
||||
list = rb_encoding_list = rb_ary_new2(ENCODING_LIST_CAPA);
|
||||
RBASIC_CLEAR_CLASS(list);
|
||||
rb_gc_register_mark_object(list);
|
||||
|
||||
@ -2024,5 +1954,5 @@ Init_encodings(void)
|
||||
void
|
||||
rb_enc_foreach_name(int (*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg)
|
||||
{
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table, st_foreach(enc_table->names, func, arg));
|
||||
st_foreach(global_enc_table.names, func, arg);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class TestEncoding < Test::Unit::TestCase
|
||||
def test_extra_encoding
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
200.times {|i|
|
||||
100.times {|i|
|
||||
EnvUtil.suppress_warning { Encoding::UTF_8.replicate("dummy#{i}") }
|
||||
}
|
||||
e = Encoding.list.last
|
||||
@ -160,4 +160,18 @@ class TestEncoding < Test::Unit::TestCase
|
||||
end
|
||||
end;
|
||||
end
|
||||
|
||||
def test_exceed_encoding_table_size
|
||||
assert_separately(%w[--disable=gems], "#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
begin
|
||||
enc = Encoding::UTF_8
|
||||
1_000.times{|i| EnvUtil.suppress_warning{ enc.replicate("R_#{i}") } } # now 256 entries
|
||||
rescue EncodingError => e
|
||||
assert_match(/too many encoding/, e.message)
|
||||
else
|
||||
assert false
|
||||
end
|
||||
end;
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user