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
34 34
    return load_path;
35 35
}
36 36

  
37
static VALUE rb_checked_expanded_cache();
38
static void rb_set_expanded_cache(VALUE);
39
static int cached_expanded_load_path = 1;
40

  
37 41
VALUE
38 42
rb_get_expanded_load_path(void)
39 43
{
40
    VALUE load_path = rb_get_load_path();
41
    VALUE ary;
42
    long i;
44
    VALUE expanded = rb_checked_expanded_cache();
43 45

  
44
    ary = rb_ary_new2(RARRAY_LEN(load_path));
45
    for (i = 0; i < RARRAY_LEN(load_path); ++i) {
46
	VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
47
	rb_str_freeze(path);
48
	rb_ary_push(ary, path);
46
    if ( !RTEST(expanded) ) {
47
	VALUE load_path = rb_get_load_path();
48
	long i;
49

  
50
	expanded = rb_ary_new2(RARRAY_LEN(load_path));
51
	for (i = 0; i < RARRAY_LEN(load_path); ++i) {
52
	    VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
53
	    rb_str_freeze(path);
54
	    rb_ary_push(expanded, path);
55
	}
56

  
57
	if (cached_expanded_load_path) {
58
	    rb_set_expanded_cache(expanded);
59
	}
60
    } else {
61
	expanded = rb_ary_dup(expanded);
49 62
    }
50
    rb_obj_freeze(ary);
51
    return ary;
63
    return expanded;
52 64
}
53 65

  
54 66
static VALUE
......
772 784
    return rb_mod_autoload_p(klass, sym);
773 785
}
774 786

  
787
// $LOAD_PATH methods which invalidates cache
788
static const char *load_path_reset_cache_methods[] = {
789
    "[]=", "collect!", "compact!", "delete",
790
    "delete_if", "fill", "flatten!", "insert", "keep_if",
791
    "map!", "reject!", "replace", "select!", "shuffle!",
792
    "sort!", "sort_by!", "uniq!", NULL
793
};
794

  
795
// $LOAD_PATH methods which sends also to cache
796
static const char *load_path_apply_to_cache_methods[] = {
797
    "clear", "delete_at", "pop", "reverse!", "rotate!",
798
    "shift", "slice!", NULL
799
};
800

  
801
// $LOAD_PATH methods which sends to cache whith expanded arguments
802
static const char *load_path_apply_expanded_methods[] = {
803
    "<<", "push", "unshift", NULL
804
};
805

  
806
static void
807
rb_reset_expanded_cache()
808
{
809
    GET_VM()->load_path_expanded_cache = 0;
810
}
811

  
812
static VALUE
813
rb_load_path_expanded_cache()
814
{
815
    VALUE cache = GET_VM()->load_path_expanded_cache;
816
    VALUE expanded = Qnil;
817
    if (RTEST(cache)) {
818
	expanded = RARRAY_PTR(cache)[1];
819
    }
820
    return expanded;
821
}
822

  
823
// Return cache only if we still in the same working directory
824
// Invalidate cache otherwise
825
static VALUE
826
rb_checked_expanded_cache()
827
{
828
    VALUE cache = GET_VM()->load_path_expanded_cache;
829
    VALUE expanded = Qnil;
830
    if (RTEST(cache)) {
831
	char *cwd = my_getcwd();
832
	VALUE curwd = RARRAY_PTR(cache)[0];
833
	if (strcmp(RSTRING_PTR(curwd), cwd)) {
834
	    rb_reset_expanded_cache();
835
	} else {
836
	    expanded = RARRAY_PTR(cache)[1];
837
	}
838
	xfree(cwd);
839
    }
840
    RB_GC_GUARD(cache);
841
    return expanded;
842
}
843

  
844
static void
845
rb_set_expanded_cache(VALUE expanded)
846
{
847
    VALUE cache = rb_ary_new2(2);
848
    char *cwd = my_getcwd();
849
    rb_ary_push(cache, rb_str_new_cstr(cwd));
850
    rb_ary_push(cache, rb_ary_dup(expanded));
851
    GET_VM()->load_path_expanded_cache = cache;
852
}
853

  
854
// Invalidating $LOAD_PATH methods implementation
855
static VALUE
856
rb_load_path_reset_cache_method(int argc, VALUE *argv, VALUE self)
857
{
858
    rb_reset_expanded_cache();
859
    return rb_call_super(argc, argv);
860
}
861

  
862
// Proxying $LOAD_PATH methods implementation
863
static VALUE
864
rb_load_path_apply_to_cache_method(int argc, VALUE *argv, VALUE self)
865
{
866
    VALUE load_path_expanded = rb_load_path_expanded_cache();
867
    if (RTEST(load_path_expanded)) {
868
	ID func = rb_frame_this_func();
869
	rb_funcall2(load_path_expanded, func, argc, argv);
870
    }
871
    return rb_call_super(argc, argv);
872
}
873

  
874
// Proxying with expansion $LOAD_PATH methods implementation
875
static VALUE
876
rb_load_path_apply_expanded_method(int argc, VALUE *argv, VALUE self)
877
{
878
    // We call methods on cache only if we still in the same working directory
879
    VALUE load_path_expanded = rb_checked_expanded_cache();
880
    if (RTEST(load_path_expanded)) {
881
	int i;
882
	ID func = rb_frame_this_func();
883
	VALUE expanded = rb_ary_new2(argc);
884
	for(i = 0; i < argc; i++) {
885
	    VALUE path = rb_file_expand_path(argv[i], Qnil);
886
	    rb_str_freeze(path);
887
	    rb_ary_push(expanded, path);
888
	}
889
	rb_funcall2(load_path_expanded, func, argc, RARRAY_PTR(expanded));
890
	RB_GC_GUARD(expanded);
891
    }
892
    return rb_call_super(argc, argv);
893
}
894
// $LOAD_PATH.concat(ary) - special, we call push(*ary) instead
895
// cause I'm lazy a bit and wish not to rewrite method above second time :)
896
static VALUE
897
rb_load_path_concat(VALUE self, VALUE ary)
898
{
899
    ID push;
900
    CONST_ID(push, "push");
901
    RB_GC_GUARD(ary);
902
    return rb_funcall2(self, push, RARRAY_LEN(ary), RARRAY_PTR(ary));
903
}
904

  
905
static VALUE
906
rb_load_path_init(void)
907
{
908
    const char **name;
909
    VALUE load_path = rb_ary_new();
910
    char *cached_flag;
911

  
912
    cached_flag = getenv("RUBY_CACHED_LOAD_PATH");
913
    if (cached_flag != NULL) {
914
	cached_expanded_load_path = atoi(cached_flag);
915
    }
916

  
917
    // Do all the magick if user did not disable it
918
    // with RUBY_CACHED_LOAD_PATH=0 environment variable
919
    if (cached_expanded_load_path) {
920
	VALUE load_path_c = rb_singleton_class(load_path);
921

  
922
	for(name = load_path_reset_cache_methods; *name; name++ ) {
923
	    rb_define_method(load_path_c, *name, rb_load_path_reset_cache_method, -1);
924
	}
925

  
926
	for(name = load_path_apply_to_cache_methods; *name; name++ ) {
927
	    rb_define_method(load_path_c, *name, rb_load_path_apply_to_cache_method, -1);
928
	}
929

  
930
	for(name = load_path_apply_expanded_methods; *name; name++ ) {
931
	    rb_define_method(load_path_c, *name, rb_load_path_apply_expanded_method, -1);
932
	}
933

  
934
	rb_define_method(load_path_c, "concat", rb_load_path_concat, 1);
935
    }
936

  
937
    rb_reset_expanded_cache();
938

  
939
    return load_path;
940
}
941

  
775 942
void
776 943
Init_load()
777 944
{
......
784 951
    rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
785 952
    rb_alias_variable(rb_intern("$-I"), id_load_path);
786 953
    rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
787
    vm->load_path = rb_ary_new();
954
    vm->load_path = rb_load_path_init();
788 955

  
789 956
    rb_define_virtual_variable("$\"", get_loaded_features, 0);
790 957
    rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
vm.c
1570 1570
	RUBY_MARK_UNLESS_NULL(vm->thgroup_default);
1571 1571
	RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
1572 1572
	RUBY_MARK_UNLESS_NULL(vm->load_path);
1573
	RUBY_MARK_UNLESS_NULL(vm->load_path_expanded_cache);
1573 1574
	RUBY_MARK_UNLESS_NULL(vm->loaded_features);
1574 1575
	RUBY_MARK_UNLESS_NULL(vm->top_self);
1575 1576
	RUBY_MARK_UNLESS_NULL(vm->coverages);
vm_core.h
298 298
    /* load */
299 299
    VALUE top_self;
300 300
    VALUE load_path;
301
    VALUE load_path_expanded_cache;
301 302
    VALUE loaded_features;
302 303
    struct st_table *loading_table;
303 304