|
From f0a7f264e53b64b0493c8de3b2d592bd5003bc0c Mon Sep 17 00:00:00 2001 |
|
From: Hiroshi Shirosaki <[email protected]> |
|
Date: Sat, 27 Oct 2012 20:50:41 +0900 |
|
Subject: [PATCH 2/3] Cache expanded relative load path |
|
|
|
* load.c (rb_construct_expanded_load_path): check relative path. |
|
We call getcwd() only if load path has relative path, to avoid getcwd() failure. |
|
|
|
* load.c (load_path_getcwd): add a function to get current working directory. |
|
|
|
* load.c (rb_get_expanded_load_path): check if current working directory is changed |
|
and rebuild expanded load path cache. |
|
|
|
* load.c (Init_load): initialize vm->load_path_cwd. |
|
|
|
* test/ruby/test_require.rb (TestRequire#test_require_): add a test for require |
|
when changeing current working directory. |
|
|
|
* vm.c (rb_vm_mark): mark vm->load_path_cwd. |
|
|
|
* vm_core.h (rb_vm_struct): add vm->load_path_cwd to store current working directory |
|
to check if expanded load path cache is invalid. |
|
--- |
|
load.c | 33 +++++++++++++++++++++++++++------ |
|
test/ruby/test_require.rb | 22 ++++++++++++++++++++++ |
|
vm.c | 1 + |
|
vm_core.h | 1 + |
|
4 files changed, 51 insertions(+), 6 deletions(-) |
|
|
|
diff --git a/load.c b/load.c |
|
index b3e316c..53dc58c 100644 |
|
--- a/load.c |
|
+++ b/load.c |
|
@@ -34,7 +34,7 @@ rb_get_load_path(void) |
|
} |
|
|
|
static void |
|
-rb_construct_expanded_load_path(int only_relative) |
|
+rb_construct_expanded_load_path(int only_relative, int *has_relative) |
|
{ |
|
rb_vm_t *vm = GET_VM(); |
|
VALUE load_path = vm->load_path; |
|
@@ -51,6 +51,8 @@ rb_construct_expanded_load_path(int only_relative) |
|
rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]); |
|
continue; |
|
} |
|
+ if (!*has_relative && !rb_is_absolute_path(StringValuePtr(as_str))) |
|
+ *has_relative = 1; |
|
if (as_str != path) |
|
rb_ary_store(load_path, i, as_str); |
|
rb_str_freeze(as_str); |
|
@@ -64,16 +66,34 @@ rb_construct_expanded_load_path(int only_relative) |
|
} |
|
|
|
static VALUE |
|
+load_path_getcwd(void) |
|
+{ |
|
+ char *cwd = my_getcwd(); |
|
+ VALUE cwd_str = rb_filesystem_str_new_cstr(cwd); |
|
+ xfree(cwd); |
|
+ return cwd_str; |
|
+} |
|
+ |
|
+static VALUE |
|
rb_get_expanded_load_path(void) |
|
{ |
|
rb_vm_t *vm = GET_VM(); |
|
+ |
|
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(0); |
|
- } |
|
- else { |
|
- /* Expand only relative load path. */ |
|
- rb_construct_expanded_load_path(1); |
|
+ int has_relative = 0; |
|
+ rb_construct_expanded_load_path(0, &has_relative); |
|
+ vm->load_path_cwd = has_relative ? load_path_getcwd() : 0; |
|
+ } |
|
+ else if (vm->load_path_cwd) { |
|
+ VALUE cwd = load_path_getcwd(); |
|
+ if (!rb_str_equal(vm->load_path_cwd, cwd)) { |
|
+ /* Current working directory or filesystem encoding was changed. |
|
+ Expand relative load path again. */ |
|
+ int has_relative = 1; |
|
+ vm->load_path_cwd = cwd; |
|
+ rb_construct_expanded_load_path(1, &has_relative); |
|
+ } |
|
} |
|
return vm->expanded_load_path; |
|
} |
|
@@ -971,6 +991,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_cwd = 0; |
|
|
|
rb_define_virtual_variable("$\"", get_loaded_features, 0); |
|
rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0); |
|
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb |
|
index a7c75d0..8c72571 100644 |
|
--- a/test/ruby/test_require.rb |
|
+++ b/test/ruby/test_require.rb |
|
@@ -435,4 +435,26 @@ class TestRequire < Test::Unit::TestCase |
|
$:.replace(loadpath) |
|
$".replace(features) |
|
end |
|
+ |
|
+ def test_require_changed_current_dir |
|
+ Dir.mktmpdir {|tmp| |
|
+ Dir.chdir(tmp) { |
|
+ Dir.mkdir("a") |
|
+ Dir.mkdir("b") |
|
+ open(File.join("a", "foo.rb"), "w") {} |
|
+ open(File.join("b", "bar.rb"), "w") {|f| |
|
+ f.puts "p :ok" |
|
+ } |
|
+ assert_in_out_err([], <<-INPUT, %w(:ok), []) |
|
+ $: << "." |
|
+ Dir.chdir("a") |
|
+ require "foo" |
|
+ Dir.chdir("../b") |
|
+ p :ng unless require "bar" |
|
+ Dir.chdir("..") |
|
+ p :ng if require "b/bar" |
|
+ INPUT |
|
+ } |
|
+ } |
|
+ end |
|
end |
|
diff --git a/vm.c b/vm.c |
|
index 9a8ebef..03cc79d 100644 |
|
--- a/vm.c |
|
+++ b/vm.c |
|
@@ -1508,6 +1508,7 @@ rb_vm_mark(void *ptr) |
|
RUBY_MARK_UNLESS_NULL(vm->mark_object_ary); |
|
RUBY_MARK_UNLESS_NULL(vm->load_path); |
|
RUBY_MARK_UNLESS_NULL(vm->load_path_snapshot); |
|
+ RUBY_MARK_UNLESS_NULL(vm->load_path_cwd); |
|
RUBY_MARK_UNLESS_NULL(vm->expanded_load_path); |
|
RUBY_MARK_UNLESS_NULL(vm->loaded_features); |
|
RUBY_MARK_UNLESS_NULL(vm->loaded_features_snapshot); |
|
diff --git a/vm_core.h b/vm_core.h |
|
index b315fe4..3874231 100644 |
|
--- a/vm_core.h |
|
+++ b/vm_core.h |
|
@@ -355,6 +355,7 @@ typedef struct rb_vm_struct { |
|
VALUE top_self; |
|
VALUE load_path; |
|
VALUE load_path_snapshot; |
|
+ VALUE load_path_cwd; |
|
VALUE expanded_load_path; |
|
VALUE loaded_features; |
|
VALUE loaded_features_snapshot; |
|
-- |
|
1.7.10.2 (Apple Git-33) |