aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNAKAMURA Usaku <usa@ruby-lang.org>2021-11-24 19:26:29 +0900
committerNAKAMURA Usaku <usa@ruby-lang.org>2021-11-24 19:26:29 +0900
commit7d4d38f8838579592e70fb04a6a2f0162fe989c2 (patch)
treeaf2cf082740d90b437bc44223b6e2dab512a3924
parent6601fb5672dc4c1f4bf5ee0f9b3f97a029df06cd (diff)
downloadruby-7d4d38f8838579592e70fb04a6a2f0162fe989c2.tar.gz
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(-)
-rw-r--r--load.c52
-rw-r--r--version.h2
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