summaryrefslogtreecommitdiff
path: root/load.c
diff options
context:
space:
mode:
Diffstat (limited to 'load.c')
-rw-r--r--load.c97
1 files changed, 89 insertions, 8 deletions
diff --git a/load.c b/load.c
index 83bc73f675..650b931661 100644
--- a/load.c
+++ b/load.c
@@ -33,22 +33,58 @@ rb_get_load_path(void)
return load_path;
}
+enum expand_type {
+ EXPAND_ALL,
+ EXPAND_RELATIVE,
+ EXPAND_HOME,
+ EXPAND_NON_CACHE
+};
+
+/* Construct expanded load path and store it to cache.
+ We rebuild load path partially if the cache is invalid.
+ We don't cache non string object and expand it every times. We ensure that
+ string objects in $LOAD_PATH are frozen.
+ */
static void
-rb_construct_expanded_load_path(void)
+rb_construct_expanded_load_path(int type, int *has_relative, int *has_non_cache)
{
rb_vm_t *vm = GET_VM();
VALUE load_path = vm->load_path;
+ VALUE expanded_load_path = vm->expanded_load_path;
VALUE ary;
long i;
+ int level = rb_safe_level();
ary = rb_ary_new2(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
VALUE path, as_str, expanded_path;
+ int is_string, non_cache;
+ char *as_cstr;
as_str = path = RARRAY_PTR(load_path)[i];
- StringValue(as_str);
- if (as_str != path)
- rb_ary_store(load_path, i, as_str);
- rb_str_freeze(as_str);
+ is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
+ non_cache = !is_string ? 1 : 0;
+ as_str = rb_get_path_check_to_string(path, level);
+ as_cstr = RSTRING_PTR(as_str);
+
+ if (!non_cache) {
+ if ((type == EXPAND_RELATIVE &&
+ rb_is_absolute_path(as_cstr)) ||
+ (type == EXPAND_HOME &&
+ (!as_cstr[0] || as_cstr[0] != '~')) ||
+ (type == EXPAND_NON_CACHE)) {
+ /* Use cached expanded path. */
+ rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
+ continue;
+ }
+ }
+ if (!*has_relative && !rb_is_absolute_path(as_cstr))
+ *has_relative = 1;
+ if (!*has_non_cache && non_cache)
+ *has_non_cache = 1;
+ /* Freeze only string object. We expand other objects every times. */
+ if (is_string)
+ rb_str_freeze(path);
+ as_str = rb_get_path_check_convert(path, as_str, level);
expanded_path = rb_file_expand_path_fast(as_str, Qnil);
rb_str_freeze(expanded_path);
rb_ary_push(ary, expanded_path);
@@ -59,12 +95,56 @@ rb_construct_expanded_load_path(void)
}
static VALUE
+load_path_getcwd(void)
+{
+ char *cwd = my_getcwd();
+ VALUE cwd_str = rb_filesystem_str_new_cstr(cwd);
+ xfree(cwd);
+ return cwd_str;
+}
+
+VALUE
rb_get_expanded_load_path(void)
{
rb_vm_t *vm = GET_VM();
+ const VALUE non_cache = Qtrue;
+
if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
- /* The load path was modified. Rebuild the expanded load path. */
- rb_construct_expanded_load_path();
+ /* The load path was modified. Rebuild the expanded load path. */
+ int has_relative = 0, has_non_cache = 0;
+ rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache);
+ if (has_relative) {
+ vm->load_path_check_cache = load_path_getcwd();
+ }
+ else if (has_non_cache) {
+ /* Non string object. */
+ vm->load_path_check_cache = non_cache;
+ }
+ else {
+ vm->load_path_check_cache = 0;
+ }
+ }
+ else if (vm->load_path_check_cache == non_cache) {
+ int has_relative = 1, has_non_cache = 1;
+ /* Expand only non-cacheable objects. */
+ rb_construct_expanded_load_path(EXPAND_NON_CACHE,
+ &has_relative, &has_non_cache);
+ }
+ else if (vm->load_path_check_cache) {
+ int has_relative = 1, has_non_cache = 1;
+ VALUE cwd = load_path_getcwd();
+ if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
+ /* Current working directory or filesystem encoding was changed.
+ Expand relative load path and non-cacheable objects again. */
+ vm->load_path_check_cache = cwd;
+ rb_construct_expanded_load_path(EXPAND_RELATIVE,
+ &has_relative, &has_non_cache);
+ }
+ else {
+ /* Expand only tilde (User HOME) and non-cacheable objects. */
+ rb_construct_expanded_load_path(EXPAND_HOME,
+ &has_relative, &has_non_cache);
+ }
}
return vm->expanded_load_path;
}
@@ -392,7 +472,7 @@ rb_feature_provided(const char *feature, const char **loading)
if (*feature == '.' &&
(feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
- fullpath = rb_file_expand_path_fast(rb_str_new2(feature), Qnil);
+ fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
feature = RSTRING_PTR(fullpath);
}
if (ext && !strchr(ext, '/')) {
@@ -963,6 +1043,7 @@ Init_load()
vm->load_path = rb_ary_new();
vm->expanded_load_path = rb_ary_new();
vm->load_path_snapshot = rb_ary_new();
+ vm->load_path_check_cache = 0;
rb_define_virtual_variable("$\"", get_loaded_features, 0);
rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);