Project

General

Profile

Feature #5767 » cache_expanded_load_path.patch

more atomic access to cache - funny_falcon (Yura Sokolov), 12/16/2011 04:10 PM

View differences:

load.c
return load_path;
}
static VALUE rb_checked_expanded_cache();
static void rb_set_expanded_cache(VALUE);
static int cached_expanded_load_path = 1;
VALUE
rb_get_expanded_load_path(void)
{
VALUE load_path = rb_get_load_path();
VALUE ary;
long i;
VALUE expanded = rb_checked_expanded_cache();
ary = rb_ary_new2(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
rb_str_freeze(path);
rb_ary_push(ary, path);
if ( !RTEST(expanded) ) {
VALUE load_path = rb_get_load_path();
long i;
expanded = rb_ary_new2(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
rb_str_freeze(path);
rb_ary_push(expanded, path);
}
if (cached_expanded_load_path) {
rb_set_expanded_cache(expanded);
}
} else {
expanded = rb_ary_dup(expanded);
}
rb_obj_freeze(ary);
return ary;
return expanded;
}
static VALUE
......
return rb_mod_autoload_p(klass, sym);
}
// $LOAD_PATH methods which invalidates cache
static const char *load_path_reset_cache_methods[] = {
"[]=", "collect!", "compact!", "delete",
"delete_if", "fill", "flatten!", "insert", "keep_if",
"map!", "reject!", "replace", "select!", "shuffle!",
"sort!", "sort_by!", "uniq!", NULL
};
// $LOAD_PATH methods which sends also to cache
static const char *load_path_apply_to_cache_methods[] = {
"clear", "delete_at", "pop", "reverse!", "rotate!",
"shift", "slice!", NULL
};
// $LOAD_PATH methods which sends to cache whith expanded arguments
static const char *load_path_apply_expanded_methods[] = {
"<<", "push", "unshift", NULL
};
static void
rb_reset_expanded_cache()
{
GET_VM()->load_path_expanded_cache = 0;
}
static VALUE
rb_load_path_expanded_cache()
{
VALUE cache = GET_VM()->load_path_expanded_cache;
VALUE expanded = Qnil;
if (RTEST(cache)) {
expanded = RARRAY_PTR(cache)[1];
}
return expanded;
}
// Return cache only if we still in the same working directory
// Invalidate cache otherwise
static VALUE
rb_checked_expanded_cache()
{
VALUE cache = GET_VM()->load_path_expanded_cache;
VALUE expanded = Qnil;
if (RTEST(cache)) {
char *cwd = my_getcwd();
VALUE curwd = RARRAY_PTR(cache)[0];
if (strcmp(RSTRING_PTR(curwd), cwd)) {
rb_reset_expanded_cache();
} else {
expanded = RARRAY_PTR(cache)[1];
}
xfree(cwd);
}
RB_GC_GUARD(cache);
return expanded;
}
static void
rb_set_expanded_cache(VALUE expanded)
{
VALUE cache = rb_ary_new2(2);
char *cwd = my_getcwd();
rb_ary_push(cache, rb_str_new_cstr(cwd));
rb_ary_push(cache, rb_ary_dup(expanded));
GET_VM()->load_path_expanded_cache = cache;
}
// Invalidating $LOAD_PATH methods implementation
static VALUE
rb_load_path_reset_cache_method(int argc, VALUE *argv, VALUE self)
{
rb_reset_expanded_cache();
return rb_call_super(argc, argv);
}
// Proxying $LOAD_PATH methods implementation
static VALUE
rb_load_path_apply_to_cache_method(int argc, VALUE *argv, VALUE self)
{
VALUE load_path_expanded = rb_load_path_expanded_cache();
if (RTEST(load_path_expanded)) {
ID func = rb_frame_this_func();
rb_funcall2(load_path_expanded, func, argc, argv);
}
return rb_call_super(argc, argv);
}
// Proxying with expansion $LOAD_PATH methods implementation
static VALUE
rb_load_path_apply_expanded_method(int argc, VALUE *argv, VALUE self)
{
// We call methods on cache only if we still in the same working directory
VALUE load_path_expanded = rb_checked_expanded_cache();
if (RTEST(load_path_expanded)) {
int i;
ID func = rb_frame_this_func();
VALUE expanded = rb_ary_new2(argc);
for(i = 0; i < argc; i++) {
VALUE path = rb_file_expand_path(argv[i], Qnil);
rb_str_freeze(path);
rb_ary_push(expanded, path);
}
rb_funcall2(load_path_expanded, func, argc, RARRAY_PTR(expanded));
RB_GC_GUARD(expanded);
}
return rb_call_super(argc, argv);
}
// $LOAD_PATH.concat(ary) - special, we call push(*ary) instead
// cause I'm lazy a bit and wish not to rewrite method above second time :)
static VALUE
rb_load_path_concat(VALUE self, VALUE ary)
{
ID push;
CONST_ID(push, "push");
RB_GC_GUARD(ary);
return rb_funcall2(self, push, RARRAY_LEN(ary), RARRAY_PTR(ary));
}
static VALUE
rb_load_path_init(void)
{
const char **name;
VALUE load_path = rb_ary_new();
char *cached_flag;
cached_flag = getenv("RUBY_CACHED_LOAD_PATH");
if (cached_flag != NULL) {
cached_expanded_load_path = atoi(cached_flag);
}
// Do all the magick if user did not disable it
// with RUBY_CACHED_LOAD_PATH=0 environment variable
if (cached_expanded_load_path) {
VALUE load_path_c = rb_singleton_class(load_path);
for(name = load_path_reset_cache_methods; *name; name++ ) {
rb_define_method(load_path_c, *name, rb_load_path_reset_cache_method, -1);
}
for(name = load_path_apply_to_cache_methods; *name; name++ ) {
rb_define_method(load_path_c, *name, rb_load_path_apply_to_cache_method, -1);
}
for(name = load_path_apply_expanded_methods; *name; name++ ) {
rb_define_method(load_path_c, *name, rb_load_path_apply_expanded_method, -1);
}
rb_define_method(load_path_c, "concat", rb_load_path_concat, 1);
}
rb_reset_expanded_cache();
return load_path;
}
void
Init_load()
{
......
rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
rb_alias_variable(rb_intern("$-I"), id_load_path);
rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
vm->load_path = rb_ary_new();
vm->load_path = rb_load_path_init();
rb_define_virtual_variable("$\"", get_loaded_features, 0);
rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
vm.c
RUBY_MARK_UNLESS_NULL(vm->thgroup_default);
RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
RUBY_MARK_UNLESS_NULL(vm->load_path);
RUBY_MARK_UNLESS_NULL(vm->load_path_expanded_cache);
RUBY_MARK_UNLESS_NULL(vm->loaded_features);
RUBY_MARK_UNLESS_NULL(vm->top_self);
RUBY_MARK_UNLESS_NULL(vm->coverages);
vm_core.h
/* load */
VALUE top_self;
VALUE load_path;
VALUE load_path_expanded_cache;
VALUE loaded_features;
struct st_table *loading_table;
(2-2/5)