diff options
author | Koichi Sasada <ko1@atdot.net> | 2020-10-13 13:16:08 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2020-10-14 14:02:06 +0900 |
commit | 11c2f0f36ccc50899a8dd69a260e85451f68b5ba (patch) | |
tree | 4d968f2742fb0cb4d260c1f2c6b2695184e21d9e | |
parent | c3ba3fa8d01aa3970dc1f4e3dc0090ae171e9e35 (diff) | |
download | ruby-11c2f0f36ccc50899a8dd69a260e85451f68b5ba.tar.gz |
sync enc_table and rb_encoding_list
enc_table which manages Encoding information. rb_encoding_list
also manages Encoding objects. Both are accessed/modified by ractors
simultaneously so that they should be synchronized.
For enc_table, this patch introduced GLOBAL_ENC_TABLE_ENTER/LEAVE/EVAL
to access this table with VM lock. To make shortcut, three new global
variables global_enc_ascii, global_enc_utf_8, global_enc_us_ascii are
also introduced.
For rb_encoding_list, we split it to rb_default_encoding_list (256 entries)
and rb_additional_encoding_list. rb_default_encoding_list is fixed sized Array
so we don't need to synchronized (and most of apps only needs it). To manage
257 or more encoding objects, they are stored into rb_additional_encoding_list.
To access rb_additional_encoding_list., VM lock is needed.
-rw-r--r-- | bootstraptest/test_ractor.rb | 14 | ||||
-rw-r--r-- | common.mk | 4 | ||||
-rw-r--r-- | encoding.c | 545 |
3 files changed, 389 insertions, 174 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 9e90d95274..05139e2081 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -780,4 +780,18 @@ assert_equal "#{N}#{N}", %Q{ }.map{|r| r.take}.join } +assert_equal "#{N/10}", %Q{ + Ractor.new do + loop do + Encoding.find("test-enc-#{rand(5_000)}").inspect + rescue ArgumentError => e + end + end + + src = Encoding.find("UTF-8") + #{N/10}.times{|i| + src.replicate("test-enc-\#{i}") + } +} + end # if !ENV['GITHUB_WORKFLOW'] @@ -4617,13 +4617,17 @@ encoding.$(OBJEXT): {$(VPATH)}internal/variable.h encoding.$(OBJEXT): {$(VPATH)}internal/warning_push.h encoding.$(OBJEXT): {$(VPATH)}internal/xmalloc.h encoding.$(OBJEXT): {$(VPATH)}missing.h +encoding.$(OBJEXT): {$(VPATH)}node.h encoding.$(OBJEXT): {$(VPATH)}onigmo.h encoding.$(OBJEXT): {$(VPATH)}oniguruma.h +encoding.$(OBJEXT): {$(VPATH)}ractor_pub.h encoding.$(OBJEXT): {$(VPATH)}regenc.h encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h encoding.$(OBJEXT): {$(VPATH)}st.h encoding.$(OBJEXT): {$(VPATH)}subst.h encoding.$(OBJEXT): {$(VPATH)}util.h +encoding.$(OBJEXT): {$(VPATH)}vm_debug.h +encoding.$(OBJEXT): {$(VPATH)}vm_sync.h enum.$(OBJEXT): $(hdrdir)/ruby.h enum.$(OBJEXT): $(hdrdir)/ruby/ruby.h enum.$(OBJEXT): $(top_srcdir)/internal/array.h diff --git a/encoding.c b/encoding.c index 7dab544efa..20bc257d4a 100644 --- a/encoding.c +++ b/encoding.c @@ -26,6 +26,8 @@ #include "ruby/encoding.h" #include "ruby/util.h" #include "ruby_assert.h" +#include "ractor_pub.h" +#include "vm_sync.h" #ifndef ENC_DEBUG #define ENC_DEBUG 0 @@ -54,7 +56,10 @@ void rb_encdb_set_unicode(int index); static ID id_encoding; VALUE rb_cEncoding; -static VALUE rb_encoding_list; + +#define DEFAULT_ENCODING_LIST_CAPA 128 +static VALUE rb_default_encoding_list; +static VALUE rb_additional_encoding_list; struct rb_encoding_entry { const char *name; @@ -62,12 +67,27 @@ struct rb_encoding_entry { rb_encoding *base; }; -static struct { +static struct enc_table { struct rb_encoding_entry *list; int count; int size; st_table *names; -} enc_table; +} global_enc_table; + +static rb_encoding *global_enc_ascii, + *global_enc_utf_8, + *global_enc_us_ascii; + +#define GLOBAL_ENC_TABLE_ENTER(enc_table) struct enc_table *enc_table = &global_enc_table; RB_VM_LOCK_ENTER() +#define GLOBAL_ENC_TABLE_LEAVE() RB_VM_LOCK_LEAVE() +#define GLOBAL_ENC_TABLE_EVAL(enc_table, expr) do { \ + GLOBAL_ENC_TABLE_ENTER(enc_table); \ + { \ + expr; \ + } \ + GLOBAL_ENC_TABLE_LEAVE(); \ +} while (0) + #define ENC_DUMMY_FLAG (1<<24) #define ENC_INDEX_MASK (~(~0U<<24)) @@ -84,8 +104,6 @@ static struct { #define enc_autoload_p(enc) (!rb_enc_mbmaxlen(enc)) -static int load_encoding(const char *name); - static const rb_data_type_t encoding_data_type = { "encoding", {0, 0, 0,}, @@ -107,19 +125,63 @@ enc_new(rb_encoding *encoding) return TypedData_Wrap_Struct(rb_cEncoding, &encoding_data_type, (void *)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(); + } +} + static VALUE -rb_enc_from_encoding_index(int idx) +enc_list_lookup(int idx) { VALUE list, enc; - if (!(list = rb_encoding_list)) { - rb_bug("rb_enc_from_encoding_index(%d): no rb_encoding_list", idx); + 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); + } + enc = rb_ary_entry(list, idx); } - 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); + rb_bug("rb_enc_from_encoding_index(%d): not created yet", idx); + } + else { + return enc; } - return enc; +} + +static VALUE +rb_enc_from_encoding_index(int idx) +{ + return enc_list_lookup(idx); } VALUE @@ -152,7 +214,7 @@ check_encoding(rb_encoding *enc) if (rb_enc_from_index(index) != enc) return -1; if (enc_autoload_p(enc)) { - index = enc_autoload(enc); + index = enc_autoload(enc); } return index; } @@ -269,26 +331,25 @@ rb_find_encoding(VALUE enc) } static int -enc_table_expand(int newsize) +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; + 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; + 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; } static int -enc_register_at(int index, const char *name, rb_encoding *base_encoding) +enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_encoding *base_encoding) { - struct rb_encoding_entry *ent = &enc_table.list[index]; + struct rb_encoding_entry *ent = &enc_table->list[index]; rb_raw_encoding *encoding; - VALUE list; if (!valid_encoding_name_p(name)) return -1; if (!ent->name) { @@ -310,76 +371,114 @@ enc_register_at(int index, const char *name, rb_encoding *base_encoding) encoding->name = name; encoding->ruby_encoding_index = index; ent->enc = encoding; - st_insert(enc_table.names, (st_data_t)name, (st_data_t)index); - list = rb_encoding_list; - if (list && NIL_P(rb_ary_entry(list, index))) { - /* initialize encoding data */ - rb_ary_store(list, index, enc_new(encoding)); - } + st_insert(enc_table->names, (st_data_t)name, (st_data_t)index); + + enc_list_update(index, encoding); return index; } static int -enc_register(const char *name, rb_encoding *encoding) +enc_register(struct enc_table *enc_table, const char *name, rb_encoding *encoding) { - int index = enc_table.count; + int index = enc_table->count; - if ((index = enc_table_expand(index + 1)) < 0) return -1; - enc_table.count = index; - return enc_register_at(index - 1, name, encoding); + if ((index = enc_table_expand(enc_table, index + 1)) < 0) return -1; + enc_table->count = index; + return enc_register_at(enc_table, index - 1, name, encoding); } static void set_encoding_const(const char *, rb_encoding *); -int rb_enc_registered(const char *name); +static int enc_registered(struct enc_table *enc_table, const char *name); + +static rb_encoding * +enc_from_index(struct enc_table *enc_table, int index) +{ + if (UNLIKELY(index < 0 || enc_table->count <= (index &= ENC_INDEX_MASK))) { + return 0; + } + return enc_table->list[index].enc; +} + +rb_encoding * +rb_enc_from_index(int index) +{ + rb_encoding *enc; + GLOBAL_ENC_TABLE_EVAL(enc_table, + enc = enc_from_index(enc_table, index)); + return enc; +} int rb_enc_register(const char *name, rb_encoding *encoding) { - int index = rb_enc_registered(name); + int index; + + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + index = enc_registered(enc_table, name); + + if (index >= 0) { + rb_encoding *oldenc = enc_from_index(enc_table, index); + if (STRCASECMP(name, rb_enc_name(oldenc))) { + index = enc_register(enc_table, name, encoding); + } + else if (enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) { + enc_register_at(enc_table, index, name, encoding); + } + else { + rb_raise(rb_eArgError, "encoding %s is already registered", name); + } + } + else { + index = enc_register(enc_table, name, encoding); + set_encoding_const(name, rb_enc_from_index(index)); + } + } + GLOBAL_ENC_TABLE_LEAVE(); + return index; +} - if (index >= 0) { - rb_encoding *oldenc = rb_enc_from_index(index); - if (STRCASECMP(name, rb_enc_name(oldenc))) { - index = enc_register(name, encoding); - } - else if (enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) { - enc_register_at(index, name, encoding); - } - else { - rb_raise(rb_eArgError, "encoding %s is already registered", name); - } - } - else { - index = enc_register(name, encoding); - set_encoding_const(name, rb_enc_from_index(index)); +int +enc_registered(struct enc_table *enc_table, const char *name) +{ + st_data_t idx = 0; + + if (!name) return -1; + if (!enc_table->list) return -1; + if (st_lookup(enc_table->names, (st_data_t)name, &idx)) { + return (int)idx; } - return index; + return -1; } void rb_encdb_declare(const char *name) { - int idx = rb_enc_registered(name); - if (idx < 0) { - idx = enc_register(name, 0); + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + int idx = enc_registered(enc_table, name); + if (idx < 0) { + idx = enc_register(enc_table, name, 0); + } + set_encoding_const(name, rb_enc_from_index(idx)); } - set_encoding_const(name, rb_enc_from_index(idx)); + GLOBAL_ENC_TABLE_LEAVE(); } static void -enc_check_duplication(const char *name) +enc_check_duplication(struct enc_table *enc_table, const char *name) { - if (rb_enc_registered(name) >= 0) { + if (enc_registered(enc_table, name) >= 0) { rb_raise(rb_eArgError, "encoding %s is already registered", name); } } static rb_encoding* -set_base_encoding(int index, rb_encoding *base) +set_base_encoding(struct enc_table *enc_table, int index, rb_encoding *base) { - rb_encoding *enc = enc_table.list[index].enc; + rb_encoding *enc = enc_table->list[index].enc; - enc_table.list[index].base = base; + enc_table->list[index].base = base; if (ENC_DUMMY_P(base)) ENC_SET_DUMMY((rb_raw_encoding *)enc); return enc; } @@ -391,9 +490,13 @@ set_base_encoding(int index, rb_encoding *base) void rb_enc_set_base(const char *name, const char *orig) { - int idx = rb_enc_registered(name); - int origidx = rb_enc_registered(orig); - set_base_encoding(idx, rb_enc_from_index(origidx)); + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + int idx = enc_registered(enc_table, name); + int origidx = enc_registered(enc_table, orig); + set_base_encoding(enc_table, idx, rb_enc_from_index(origidx)); + } + GLOBAL_ENC_TABLE_LEAVE(); } /* for encdb.h @@ -402,24 +505,38 @@ rb_enc_set_base(const char *name, const char *orig) int rb_enc_set_dummy(int index) { - rb_encoding *enc = enc_table.list[index].enc; + rb_encoding *enc; + + GLOBAL_ENC_TABLE_EVAL(enc_table, + enc = enc_table->list[index].enc); ENC_SET_DUMMY((rb_raw_encoding *)enc); return index; } -int -rb_enc_replicate(const char *name, rb_encoding *encoding) +static int +enc_replicate(struct enc_table *enc_table, const char *name, rb_encoding *encoding) { int idx; - enc_check_duplication(name); - idx = enc_register(name, encoding); - set_base_encoding(idx, encoding); + enc_check_duplication(enc_table, name); + idx = enc_register(enc_table, name, encoding); + set_base_encoding(enc_table, idx, encoding); set_encoding_const(name, rb_enc_from_index(idx)); return idx; } +int +rb_enc_replicate(const char *name, rb_encoding *encoding) +{ + int r; + + GLOBAL_ENC_TABLE_EVAL(enc_table, + r = enc_replicate(enc_table, name, encoding)); + + return r; +} + /* * call-seq: * enc.replicate(name) -> encoding @@ -430,7 +547,7 @@ rb_enc_replicate(const char *name, rb_encoding *encoding) * */ static VALUE -enc_replicate(VALUE encoding, VALUE name) +enc_replicate_m(VALUE encoding, VALUE name) { return rb_enc_from_encoding_index( rb_enc_replicate(StringValueCStr(name), @@ -438,16 +555,16 @@ enc_replicate(VALUE encoding, VALUE name) } static int -enc_replicate_with_index(const char *name, rb_encoding *origenc, int idx) +enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encoding *origenc, int idx) { if (idx < 0) { - idx = enc_register(name, origenc); + idx = enc_register(enc_table, name, origenc); } else { - idx = enc_register_at(idx, name, origenc); + idx = enc_register_at(enc_table, idx, name, origenc); } if (idx >= 0) { - set_base_encoding(idx, origenc); + set_base_encoding(enc_table, idx, origenc); set_encoding_const(name, rb_enc_from_index(idx)); } else { @@ -459,33 +576,54 @@ enc_replicate_with_index(const char *name, rb_encoding *origenc, int idx) int rb_encdb_replicate(const char *name, const char *orig) { - int origidx = rb_enc_registered(orig); - int idx = rb_enc_registered(name); + int r; - if (origidx < 0) { - origidx = enc_register(orig, 0); + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + int origidx = enc_registered(enc_table, orig); + int idx = enc_registered(enc_table, name); + + if (origidx < 0) { + origidx = enc_register(enc_table, orig, 0); + } + r = enc_replicate_with_index(enc_table, name, rb_enc_from_index(origidx), idx); } - return enc_replicate_with_index(name, rb_enc_from_index(origidx), idx); + GLOBAL_ENC_TABLE_LEAVE(); + + return r; } int rb_define_dummy_encoding(const char *name) { - int index = rb_enc_replicate(name, rb_ascii8bit_encoding()); - rb_encoding *enc = enc_table.list[index].enc; + int index; + + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + index = enc_replicate(enc_table, name, rb_ascii8bit_encoding()); + rb_encoding *enc = enc_table->list[index].enc; + ENC_SET_DUMMY((rb_raw_encoding *)enc); + } + GLOBAL_ENC_TABLE_LEAVE(); - ENC_SET_DUMMY((rb_raw_encoding *)enc); return index; } int rb_encdb_dummy(const char *name) { - int index = enc_replicate_with_index(name, rb_ascii8bit_encoding(), - rb_enc_registered(name)); - rb_encoding *enc = enc_table.list[index].enc; + int index; + + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + index = enc_replicate_with_index(enc_table, name, + rb_ascii8bit_encoding(), + enc_registered(enc_table, name)); + rb_encoding *enc = enc_table->list[index].enc; + ENC_SET_DUMMY((rb_raw_encoding *)enc); + } + GLOBAL_ENC_TABLE_LEAVE(); - ENC_SET_DUMMY((rb_raw_encoding *)enc); return index; } @@ -544,42 +682,58 @@ enc_dup_name(st_data_t name) * else returns NULL. */ static int -enc_alias_internal(const char *alias, int idx) +enc_alias_internal(struct enc_table *enc_table, const char *alias, int idx) { - return st_insert2(enc_table.names, (st_data_t)alias, (st_data_t)idx, + return st_insert2(enc_table->names, (st_data_t)alias, (st_data_t)idx, enc_dup_name); } static int -enc_alias(const char *alias, int idx) +enc_alias(struct enc_table *enc_table, const char *alias, int idx) { if (!valid_encoding_name_p(alias)) return -1; - if (!enc_alias_internal(alias, idx)) - set_encoding_const(alias, rb_enc_from_index(idx)); + if (!enc_alias_internal(enc_table, alias, idx)) + set_encoding_const(alias, enc_from_index(enc_table, idx)); return idx; } int rb_enc_alias(const char *alias, const char *orig) { - int idx; + int idx, r; - enc_check_duplication(alias); - if ((idx = rb_enc_find_index(orig)) < 0) { - return -1; + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + enc_check_duplication(enc_table, alias); + if ((idx = rb_enc_find_index(orig)) < 0) { + r = -1; + } + else { + r = enc_alias(enc_table, alias, idx); + } } - return enc_alias(alias, idx); + GLOBAL_ENC_TABLE_LEAVE(); + + return r; } int rb_encdb_alias(const char *alias, const char *orig) { - int idx = rb_enc_registered(orig); + int r; - if (idx < 0) { - idx = enc_register(orig, 0); + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + int idx = enc_registered(enc_table, orig); + + if (idx < 0) { + idx = enc_register(enc_table, orig, 0); + } + r = enc_alias(enc_table, alias, idx); } - return enc_alias(alias, idx); + GLOBAL_ENC_TABLE_LEAVE(); + + return r; } void @@ -588,19 +742,22 @@ rb_encdb_set_unicode(int index) ((rb_raw_encoding *)rb_enc_from_index(index))->flags |= ONIGENC_FLAG_UNICODE; } -void -rb_enc_init(void) +static void +rb_enc_init(struct enc_table *enc_table) { - enc_table_expand(ENCODING_COUNT + 1); - if (!enc_table.names) { - enc_table.names = st_init_strcasetable(); + enc_table_expand(enc_table, ENCODING_COUNT + 1); + if (!enc_table->names) { + enc_table->names = st_init_strcasetable(); } -#define ENC_REGISTER(enc) enc_register_at(ENCINDEX_##enc, rb_enc_name(&OnigEncoding##enc), &OnigEncoding##enc) +#define ENC_REGISTER(enc) enc_register_at(enc_table, ENCINDEX_##enc, rb_enc_name(&OnigEncoding##enc), &OnigEncoding##enc) ENC_REGISTER(ASCII); ENC_REGISTER(UTF_8); ENC_REGISTER(US_ASCII); + global_enc_ascii = enc_table->list[ENCINDEX_ASCII].enc; + global_enc_utf_8 = enc_table->list[ENCINDEX_UTF_8].enc; + global_enc_us_ascii = enc_table->list[ENCINDEX_US_ASCII].enc; #undef ENC_REGISTER -#define ENCDB_REGISTER(name, enc) enc_register_at(ENCINDEX_##enc, name, NULL) +#define ENCDB_REGISTER(name, enc) enc_register_at(enc_table, ENCINDEX_##enc, name, NULL) ENCDB_REGISTER("UTF-16BE", UTF_16BE); ENCDB_REGISTER("UTF-16LE", UTF_16LE); ENCDB_REGISTER("UTF-32BE", UTF_32BE); @@ -612,16 +769,7 @@ rb_enc_init(void) ENCDB_REGISTER("EUC-JP", EUC_JP); ENCDB_REGISTER("Windows-31J", Windows_31J); #undef ENCDB_REGISTER - enc_table.count = ENCINDEX_BUILTIN_MAX; -} - -rb_encoding * -rb_enc_from_index(int index) -{ - if (UNLIKELY(index < 0 || enc_table.count <= (index &= ENC_INDEX_MASK))) { - return 0; - } - return enc_table.list[index].enc; + enc_table->count = ENCINDEX_BUILTIN_MAX; } rb_encoding * @@ -630,19 +778,6 @@ rb_enc_get_from_index(int index) return must_encindex(index); } -int -rb_enc_registered(const char *name) -{ - st_data_t idx = 0; - - if (!name) return -1; - if (!enc_table.list) return -1; - if (st_lookup(enc_table.names, (st_data_t)name, &idx)) { - return (int)idx; - } - return -1; -} - static int load_encoding(const char *name) { @@ -667,33 +802,55 @@ load_encoding(const char *name) ruby_verbose = verbose; ruby_debug = debug; rb_set_errinfo(errinfo); - if (loaded < 0 || 1 < loaded) return -1; - if ((idx = rb_enc_registered(name)) < 0) return -1; - if (enc_autoload_p(enc_table.list[idx].enc)) return -1; + + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + if (loaded < 0 || 1 < loaded) { + idx = -1; + } + else if ((idx = enc_registered(enc_table, name)) < 0) { + idx = -1; + } + else if (enc_autoload_p(enc_table->list[idx].enc)) { + idx = -1; + } + } + GLOBAL_ENC_TABLE_LEAVE(); + return idx; } static int -enc_autoload(rb_encoding *enc) +enc_autoload_body(struct enc_table *enc_table, rb_encoding *enc) { - int i; - rb_encoding *base = enc_table.list[ENC_TO_ENCINDEX(enc)].base; + rb_encoding *base = enc_table->list[ENC_TO_ENCINDEX(enc)].base; if (base) { - i = 0; + int i = 0; do { - if (i >= enc_table.count) return -1; - } while (enc_table.list[i].enc != base && (++i, 1)); + if (i >= enc_table->count) return -1; + } while (enc_table->list[i].enc != base && (++i, 1)); if (enc_autoload_p(base)) { if (enc_autoload(base) < 0) return -1; } i = enc->ruby_encoding_index; - enc_register_at(i & ENC_INDEX_MASK, rb_enc_name(enc), base); - ((rb_raw_encoding *)enc)->ruby_encoding_index = i; + enc_register_at(enc_table, i & ENC_INDEX_MASK, rb_enc_name(enc), base); + ((rb_raw_encoding *)enc)->ruby_encoding_index = i; i &= ENC_INDEX_MASK; + return i; } else { - i = load_encoding(rb_enc_name(enc)); + return -2; + } +} + +static int +enc_autoload(rb_encoding *enc) +{ + int i; + GLOBAL_ENC_TABLE_EVAL(enc_table, i = enc_autoload_body(enc_table, enc)); + if (i == -2) { + i = load_encoding(rb_enc_name(enc)); } return i; } @@ -702,9 +859,11 @@ enc_autoload(rb_encoding *enc) int rb_enc_find_index(const char *name) { - int i = rb_enc_registered(name); + int i; rb_encoding *enc; + GLOBAL_ENC_TABLE_EVAL(enc_table, i = enc_registered(enc_table, name)); + if (i < 0) { i = load_encoding(name); } @@ -1203,7 +1362,10 @@ enc_names(VALUE self) args[0] = (VALUE)rb_to_encoding_index(self); args[1] = rb_ary_new2(0); - st_foreach(enc_table.names, enc_names_i, (st_data_t)args); + + GLOBAL_ENC_TABLE_EVAL(enc_table, + st_foreach(enc_table->names, enc_names_i, (st_data_t)args)); + return args[1]; } @@ -1229,7 +1391,14 @@ static VALUE enc_list(VALUE klass) { VALUE ary = rb_ary_new2(0); - rb_ary_replace(ary, rb_encoding_list); + + RB_VM_LOCK_ENTER(); + { + rb_ary_replace(ary, rb_default_encoding_list); + rb_ary_concat(ary, rb_additional_encoding_list); + } + RB_VM_LOCK_LEAVE(); + return ary; } @@ -1336,7 +1505,7 @@ enc_m_loader(VALUE klass, VALUE str) rb_encoding * rb_ascii8bit_encoding(void) { - return enc_table.list[ENCINDEX_ASCII].enc; + return global_enc_ascii; } int @@ -1348,7 +1517,7 @@ rb_ascii8bit_encindex(void) rb_encoding * rb_utf8_encoding(void) { - return enc_table.list[ENCINDEX_UTF_8].enc; + return global_enc_utf_8; } int @@ -1360,7 +1529,7 @@ rb_utf8_encindex(void) rb_encoding * rb_usascii_encoding(void) { - return enc_table.list[ENCINDEX_US_ASCII].enc; + return global_enc_us_ascii; } int @@ -1378,13 +1547,15 @@ rb_locale_encindex(void) if (idx < 0) idx = ENCINDEX_UTF_8; - if (rb_enc_registered("locale") < 0) { + GLOBAL_ENC_TABLE_ENTER(enc_table); + if (enc_registered(enc_table, "locale") < 0) { # if defined _WIN32 void Init_w32_codepage(void); Init_w32_codepage(); # endif - enc_alias_internal("locale", idx); + enc_alias_internal(enc_table, "locale", idx); } + GLOBAL_ENC_TABLE_LEAVE(); return idx; } @@ -1398,7 +1569,11 @@ rb_locale_encoding(void) int rb_filesystem_encindex(void) { - int idx = rb_enc_registered("filesystem"); + int idx; + + GLOBAL_ENC_TABLE_EVAL(enc_table, + idx = enc_registered(enc_table, "filesystem")); + if (idx < 0) idx = ENCINDEX_ASCII; return idx; @@ -1426,20 +1601,25 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha /* Already set */ overridden = TRUE; - if (NIL_P(encoding)) { - def->index = -1; - def->enc = 0; - st_insert(enc_table.names, (st_data_t)strdup(name), - (st_data_t)UNSPECIFIED_ENCODING); - } - else { - def->index = rb_enc_to_index(rb_to_encoding(encoding)); - def->enc = 0; - enc_alias_internal(name, def->index); - } - - if (def == &default_external) - enc_alias_internal("filesystem", Init_enc_set_filesystem_encoding()); + GLOBAL_ENC_TABLE_ENTER(enc_table); + { + if (NIL_P(encoding)) { + def->index = -1; + def->enc = 0; + st_insert(enc_table->names, (st_data_t)strdup(name), + (st_data_t)UNSPECIFIED_ENCODING); + } + else { + def->index = rb_enc_to_index(rb_to_encoding(encoding)); + def->enc = 0; + enc_alias_internal(enc_table, name, def->index); + } + + if (def == &default_external) { + enc_alias_internal(enc_table, "filesystem", Init_enc_set_filesystem_encoding()); + } + } + GLOBAL_ENC_TABLE_LEAVE(); return overridden; } @@ -1684,8 +1864,15 @@ 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 = rb_ary_new2(enc_table.names->num_entries); - st_foreach(enc_table.names, rb_enc_name_list_i, (st_data_t)ary); + 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(); + return ary; } @@ -1730,7 +1917,10 @@ rb_enc_aliases(VALUE klass) VALUE aliases[2]; aliases[0] = rb_hash_new(); aliases[1] = rb_ary_new(); - st_foreach(enc_table.names, rb_enc_aliases_enc_i, (st_data_t)aliases); + + GLOBAL_ENC_TABLE_EVAL(enc_table, + st_foreach(enc_table->names, rb_enc_aliases_enc_i, (st_data_t)aliases)); + return aliases[0]; } @@ -1952,7 +2142,7 @@ Init_Encoding(void) rb_define_method(rb_cEncoding, "names", enc_names, 0); rb_define_method(rb_cEncoding, "dummy?", enc_dummy_p, 0); rb_define_method(rb_cEncoding, "ascii_compatible?", enc_ascii_compatible_p, 0); - rb_define_method(rb_cEncoding, "replicate", enc_replicate, 1); + rb_define_method(rb_cEncoding, "replicate", enc_replicate_m, 1); rb_define_singleton_method(rb_cEncoding, "list", enc_list, 0); rb_define_singleton_method(rb_cEncoding, "name_list", rb_enc_name_list, 0); rb_define_singleton_method(rb_cEncoding, "aliases", rb_enc_aliases, 0); @@ -1968,13 +2158,20 @@ Init_Encoding(void) rb_define_singleton_method(rb_cEncoding, "default_internal=", set_default_internal, 1); rb_define_singleton_method(rb_cEncoding, "locale_charmap", rb_locale_charmap, 0); /* in localeinit.c */ - list = rb_ary_new2(enc_table.count); + 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); RBASIC_CLEAR_CLASS(list); - rb_encoding_list = list; rb_gc_register_mark_object(list); - for (i = 0; i < enc_table.count; ++i) { - rb_ary_push(list, enc_new(enc_table.list[i].enc)); + for (i = 0; i < enc_table->count; ++i) { + rb_ary_push(list, enc_new(enc_table->list[i].enc)); } rb_marshal_define_compat(rb_cEncoding, Qnil, 0, enc_m_loader); @@ -1983,7 +2180,7 @@ Init_Encoding(void) void Init_encodings(void) { - rb_enc_init(); + rb_enc_init(&global_enc_table); } /* locale insensitive ctype functions */ @@ -1991,5 +2188,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) { - st_foreach(enc_table.names, func, arg); + GLOBAL_ENC_TABLE_EVAL(enc_table, st_foreach(enc_table->names, func, arg)); } |