From 7d4d38f8838579592e70fb04a6a2f0162fe989c2 Mon Sep 17 00:00:00 2001 From: NAKAMURA Usaku Date: Wed, 24 Nov 2021 19:26:29 +0900 Subject: merge revision(s) b360588cd3cbac5fb4f004aa53a8fdc715906719: [Backport #15856] Sort feature index arrays by the priority of file types [Bug #15856] When looking for libraries to load with a feature name without extension, `.rb` files are given priority. However, since the feature index arrays were not in that order of priority, but in the order in which they were loaded, a lower priority extension library might be returned. In that case, the `.rb` file had to be searched for again from the `$LOAD_PATH`, resulting in poor performance. --- load.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) --- load.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- version.h | 2 +- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/load.c b/load.c index 07acc9ac79..408339e051 100644 --- a/load.c +++ b/load.c @@ -178,8 +178,17 @@ feature_key(const char *str, size_t len) return st_hash(str, len, 0xfea7009e); } +static bool +is_rbext_path(VALUE feature_path) +{ + long len = RSTRING_LEN(feature_path); + long rbext_len = rb_strlen_lit(".rb"); + if (len <= rbext_len) return false; + return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len); +} + static void -features_index_add_single(const char* str, size_t len, VALUE offset) +features_index_add_single(const char* str, size_t len, VALUE offset, bool rb) { struct st_table *features_index; VALUE this_feature_index = Qnil; @@ -195,17 +204,43 @@ features_index_add_single(const char* str, size_t len, VALUE offset) st_insert(features_index, short_feature_key, (st_data_t)offset); } else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) { + VALUE loaded_features = get_loaded_features(); + VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index)); VALUE feature_indexes[2]; - feature_indexes[0] = this_feature_index; - feature_indexes[1] = offset; + int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0; + feature_indexes[top^0] = this_feature_index; + feature_indexes[top^1] = offset; this_feature_index = (VALUE)xcalloc(1, sizeof(struct RArray)); RBASIC(this_feature_index)->flags = T_ARRAY; /* fake VALUE, do not mark/sweep */ rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes)); st_insert(features_index, short_feature_key, (st_data_t)this_feature_index); } else { + long pos = -1; + Check_Type(this_feature_index, T_ARRAY); + if (rb) { + VALUE loaded_features = get_loaded_features(); + for (long i = 0; i < RARRAY_LEN(this_feature_index); ++i) { + VALUE idx = RARRAY_AREF(this_feature_index, i); + VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(idx)); + Check_Type(this_feature_path, T_STRING); + if (!is_rbext_path(this_feature_path)) { + /* as this_feature_index is a fake VALUE, `push` (which + * doesn't wb_unprotect like as rb_ary_splice) first, + * then rotate partially. */ + pos = i; + break; + } + } + } rb_ary_push(this_feature_index, offset); + if (pos >= 0) { + VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(this_feature_index); + long len = RARRAY_LEN(this_feature_index); + MEMMOVE(ptr + pos, ptr + pos + 1, VALUE, len - pos - 1); + ptr[pos] = offset; + } } } @@ -221,6 +256,7 @@ static void features_index_add(VALUE feature, VALUE offset) { const char *feature_str, *feature_end, *ext, *p; + bool rb = false; feature_str = StringValuePtr(feature); feature_end = feature_str + RSTRING_LEN(feature); @@ -230,6 +266,8 @@ features_index_add(VALUE feature, VALUE offset) break; if (*ext != '.') ext = NULL; + else + rb = IS_RBEXT(ext); /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is at the end of `feature`, or is NULL if there is no such string. */ @@ -241,14 +279,14 @@ features_index_add(VALUE feature, VALUE offset) if (p < feature_str) break; /* Now *p == '/'. We reach this point for every '/' in `feature`. */ - features_index_add_single(p + 1, feature_end - p - 1, offset); + features_index_add_single(p + 1, feature_end - p - 1, offset, false); if (ext) { - features_index_add_single(p + 1, ext - p - 1, offset); + features_index_add_single(p + 1, ext - p - 1, offset, rb); } } - features_index_add_single(feature_str, feature_end - feature_str, offset); + features_index_add_single(feature_str, feature_end - feature_str, offset, false); if (ext) { - features_index_add_single(feature_str, ext - feature_str, offset); + features_index_add_single(feature_str, ext - feature_str, offset, rb); } } diff --git a/version.h b/version.h index 5f87ab38ee..dbc8f4bbf2 100644 --- a/version.h +++ b/version.h @@ -2,7 +2,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 5 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 193 +#define RUBY_PATCHLEVEL 194 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 11 -- cgit v1.2.3