Project

General

Profile

Feature #5767 ยป cache_expanded_load_path.patch

refactor methods a bit. - funny_falcon (Yura Sokolov), 12/19/2011 03:57 PM

View differences:

file.c
2821 2821
    buflen = RSTRING_LEN(result),\
2822 2822
    pend = p + buflen)
2823 2823

  
2824
#define EXPAND_PATH()\
2825
    if ( !(abs_mode & FEP_DIR_EXPANDED) ) { \
2826
	file_expand_path(dname, Qnil, abs_mode, result); \
2827
    } \
2828
    else { \
2829
	size_t dlen = RSTRING_LEN(dname); \
2830
	BUFCHECK(dlen > buflen); \
2831
	strncpy(buf, RSTRING_PTR(dname), dlen + 1); \
2832
	rb_str_set_len(result, dlen); \
2833
	rb_enc_associate(result, rb_enc_check(result, dname)); \
2834
	ENC_CODERANGE_CLEAR(result); \
2835
    }
2836

  
2837

  
2824 2838
VALUE
2825 2839
rb_home_dir(const char *user, VALUE result)
2826 2840
{
......
2865 2879
    return result;
2866 2880
}
2867 2881

  
2882
#define FEP_FILE_ABSOLUTE 1
2883
#define FEP_DIR_EXPANDED 2
2868 2884
static VALUE
2869 2885
file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
2870 2886
{
......
2877 2893
    BUFINIT();
2878 2894
    tainted = OBJ_TAINTED(fname);
2879 2895

  
2880
    if (s[0] == '~' && abs_mode == 0) {      /* execute only if NOT absolute_path() */
2896
    if (s[0] == '~' && !(abs_mode & FEP_FILE_ABSOLUTE)) {      /* execute only if NOT absolute_path() */
2881 2897
	long userlen = 0;
2882 2898
	tainted = 1;
2883 2899
	if (isdirsep(s[1]) || s[1] == '\0') {
......
2925 2941
	    /* specified drive, but not full path */
2926 2942
	    int same = 0;
2927 2943
	    if (!NIL_P(dname) && !not_same_drive(dname, s[0])) {
2928
		file_expand_path(dname, Qnil, abs_mode, result);
2944
		EXPAND_PATH();
2929 2945
		BUFINIT();
2930 2946
		if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) {
2931 2947
		    /* ok, same drive */
......
2951 2967
#endif
2952 2968
    else if (!rb_is_absolute_path(s)) {
2953 2969
	if (!NIL_P(dname)) {
2954
	    file_expand_path(dname, Qnil, abs_mode, result);
2970
	    EXPAND_PATH();
2955 2971
	    BUFINIT();
2956 2972
	    rb_enc_associate(result, rb_enc_check(result, fname));
2957 2973
	}
......
3235 3251
rb_file_absolute_path(VALUE fname, VALUE dname)
3236 3252
{
3237 3253
    check_expand_path_args(fname, dname);
3238
    return file_expand_path(fname, dname, 1, EXPAND_PATH_BUFFER());
3254
    return file_expand_path(fname, dname, FEP_FILE_ABSOLUTE, EXPAND_PATH_BUFFER());
3239 3255
}
3240 3256

  
3241 3257
/*
......
5109 5125
    return rb_find_file_ext_safe(filep, ext, rb_safe_level());
5110 5126
}
5111 5127

  
5128
#define GET_LOAD_PATH() \
5129
    if (cached_expanded_load_path) { \
5130
	RB_GC_GUARD(load_path) = rb_get_expanded_load_path(); \
5131
	dirs_mode = FEP_DIR_EXPANDED; \
5132
    } \
5133
    else { \
5134
	RB_GC_GUARD(load_path) = rb_get_load_path(); \
5135
	dirs_mode = 0; \
5136
    }
5137

  
5112 5138
int
5113 5139
rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
5114 5140
{
5115 5141
    const char *f = StringValueCStr(*filep);
5116 5142
    VALUE fname = *filep, load_path, tmp;
5117 5143
    long i, j, fnlen;
5118
    int expanded = 0;
5144
    int expanded = 0, dirs_mode;
5119 5145

  
5120 5146
    if (!ext[0]) return 0;
5121 5147

  
......
5150 5176
	rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
5151 5177
    }
5152 5178

  
5153
    RB_GC_GUARD(load_path) = rb_get_load_path();
5179
    GET_LOAD_PATH();
5154 5180
    if (!load_path) return 0;
5155 5181

  
5156 5182
    fname = rb_str_dup(*filep);
......
5164 5190

  
5165 5191
	    RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
5166 5192
	    if (RSTRING_LEN(str) == 0) continue;
5167
	    file_expand_path(fname, str, 0, tmp);
5193
	    file_expand_path(fname, str, dirs_mode, tmp);
5168 5194
	    if (file_load_ok(RSTRING_PTR(tmp))) {
5169 5195
		*filep = copy_path_class(tmp, *filep);
5170 5196
		return (int)(j+1);
......
5188 5214
{
5189 5215
    VALUE tmp, load_path;
5190 5216
    const char *f = StringValueCStr(path);
5191
    int expanded = 0;
5217
    int expanded = 0, dirs_mode;
5192 5218

  
5193 5219
    if (f[0] == '~') {
5194 5220
	tmp = file_expand_path_1(path);
......
5214 5240
	rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
5215 5241
    }
5216 5242

  
5217
    RB_GC_GUARD(load_path) = rb_get_load_path();
5243
    GET_LOAD_PATH();
5218 5244
    if (load_path) {
5219 5245
	long i;
5220 5246

  
......
5223 5249
	    VALUE str = RARRAY_PTR(load_path)[i];
5224 5250
	    RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
5225 5251
	    if (RSTRING_LEN(str) > 0) {
5226
		file_expand_path(path, str, 0, tmp);
5252
		file_expand_path(path, str, dirs_mode, tmp);
5227 5253
		f = RSTRING_PTR(tmp);
5228 5254
		if (file_load_ok(f)) goto found;
5229 5255
	    }
internal.h
109 109

  
110 110
/* load.c */
111 111
VALUE rb_get_load_path(void);
112
VALUE rb_get_expanded_load_path(void);
113
void rb_reset_expanded_cache();
114
void rb_load_path_ary_push(VALUE path);
115
extern int cached_expanded_load_path;
112 116

  
113 117
/* math.c */
114 118
VALUE rb_math_atan2(VALUE, VALUE);
load.c
4 4

  
5 5
#include "ruby/ruby.h"
6 6
#include "ruby/util.h"
7
#include "ruby/encoding.h"
7 8
#include "internal.h"
8 9
#include "dln.h"
9 10
#include "eval_intern.h"
......
18 19
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
19 20
#endif
20 21

  
21

  
22 22
static const char *const loadable_ext[] = {
23 23
    ".rb", DLEXT,
24 24
#ifdef DLEXT2
......
34 34
    return load_path;
35 35
}
36 36

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

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

  
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);
47
    if ( !RTEST(expanded) ) {
48
	VALUE load_path = rb_get_load_path();
49
	int has_relative = 0;
50

  
51
	if (!load_path) return 0;
52

  
53
	expanded = rb_expand_load_paths(
54
			RARRAY_LEN(load_path), RARRAY_PTR(load_path),
55
			&has_relative);
56
	RB_GC_GUARD(load_path);
57

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

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

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

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

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

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

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

  
824
// Return cache only if we still in the same working directory
825
// and filesystem_encoding didn't change
826
// Invalidate cache otherwise
827
static VALUE
828
rb_checked_expanded_cache(int *has_relative)
829
{
830
    VALUE cache = GET_VM()->load_path_expanded_cache;
831
    VALUE expanded = Qnil;
832
    if (RTEST(cache)) {
833
	VALUE curwd = RARRAY_PTR(cache)[0];
834
	VALUE encindex = RARRAY_PTR(cache)[1];
835
	int cache_valid = rb_filesystem_encindex() == FIX2INT(encindex);
836

  
837
	if ( cache_valid ) {
838
	    cache_valid = curwd == Qtrue;
839
	    if (has_relative) {
840
		*has_relative = cache_valid;
841
	    }
842
	    if (!cache_valid ) {
843
		char *cwd = my_getcwd();
844
		cache_valid = !strcmp(RSTRING_PTR(curwd), cwd);
845
		xfree(cwd);
846
	    }
847
	}
848

  
849
	if ( !cache_valid ) {
850
	    rb_reset_expanded_cache();
851
	} else {
852
	    expanded = RARRAY_PTR(cache)[2];
853
	}
854
    }
855
    RB_GC_GUARD(cache);
856
    return expanded;
857
}
858

  
859
static void
860
rb_set_expanded_cache(VALUE expanded, int has_relative)
861
{
862
    VALUE cache = rb_ary_new2(2);
863

  
864
    if (has_relative) {
865
	char *cwd = my_getcwd();
866
	rb_ary_push(cache, rb_str_new_cstr(cwd));
867
	xfree(cwd);
868
    } else {
869
	rb_ary_push(cache, Qtrue);
870
    }
871

  
872
    rb_ary_push(cache, INT2FIX(rb_filesystem_encindex()));
873
    rb_ary_push(cache, rb_ary_dup(expanded));
874
    GET_VM()->load_path_expanded_cache = cache;
875
}
876

  
877
static VALUE
878
rb_expand_load_paths(int pathc, VALUE* paths, int *has_relative)
879
{
880
    int i;
881
    const char *p;
882
    VALUE path, expanded = rb_ary_new2(pathc);
883

  
884
    for(i = 0; i < pathc; i++) {
885
	path = rb_get_path(paths[i]);
886
	p = RSTRING_PTR(path);
887
	*has_relative = *has_relative || !rb_is_absolute_path(p);
888
	path = rb_file_expand_path(path, Qnil);
889
	rb_str_freeze(path);
890
	rb_ary_push(expanded, path);
891
    }
892

  
893
    return expanded;
894
}
895

  
896
// Invalidating $LOAD_PATH methods implementation
897
static VALUE
898
rb_load_path_reset_cache_method(int argc, VALUE *argv, VALUE self)
899
{
900
    rb_reset_expanded_cache();
901
    return rb_call_super(argc, argv);
902
}
903

  
904
// Proxying $LOAD_PATH methods implementation
905
static VALUE
906
rb_load_path_apply_to_cache_method(int argc, VALUE *argv, VALUE self)
907
{
908
    VALUE load_path_expanded = rb_load_path_expanded_cache();
909
    if (RTEST(load_path_expanded)) {
910
	ID func = rb_frame_this_func();
911
	rb_funcall2(load_path_expanded, func, argc, argv);
912
    }
913
    return rb_call_super(argc, argv);
914
}
915

  
916
// Proxying with expansion $LOAD_PATH methods implementation
917
static VALUE
918
rb_load_path_apply_expanded_method(int argc, VALUE *argv, VALUE self)
919
{
920
    int old_has_relative = 0;
921
    // We call methods on cache only if we still in the same working directory
922
    VALUE load_path_expanded = rb_checked_expanded_cache(&old_has_relative);
923
    if (RTEST(load_path_expanded)) {
924
	int has_relative = 0;
925
	ID func = rb_frame_this_func();
926
	VALUE expanded = rb_expand_load_paths(argc, argv, &has_relative);
927

  
928
	rb_funcall2(load_path_expanded, func, argc, RARRAY_PTR(expanded));
929

  
930
	if (!old_has_relative && has_relative) {
931
	    rb_set_expanded_cache(load_path_expanded, has_relative);
932
	}
933
	RB_GC_GUARD(expanded);
934
    }
935
    return rb_call_super(argc, argv);
936
}
937
// $LOAD_PATH.concat(ary) - special, we call push(*ary) instead
938
// cause I'm lazy a bit and wish not to rewrite method above second time :)
939
static VALUE
940
rb_load_path_concat(VALUE self, VALUE ary)
941
{
942
    ID push;
943
    CONST_ID(push, "push");
944
    RB_GC_GUARD(ary);
945
    return rb_funcall2(self, push, RARRAY_LEN(ary), RARRAY_PTR(ary));
946
}
947

  
948
void
949
rb_load_path_ary_push(VALUE path)
950
{
951
    int old_has_relative = 0;
952
    VALUE load_path_expanded = rb_checked_expanded_cache(&old_has_relative);
953
    if (RTEST(load_path_expanded)) {
954
	int has_relative = 0;
955
	VALUE expanded = rb_expand_load_paths(1, &path, &has_relative);
956

  
957
	rb_ary_push(load_path_expanded, RARRAY_PTR(expanded)[0]);
958

  
959
	if (!old_has_relative && has_relative) {
960
	    rb_set_expanded_cache(load_path_expanded, has_relative);
961
	}
962
	RB_GC_GUARD(expanded);
963
    }
964

  
965
    rb_ary_push(rb_get_load_path(), path);
966
}
967

  
968
static VALUE
969
rb_load_path_init(void)
970
{
971
    const char **name;
972
    VALUE load_path = rb_ary_new();
973
    char *cached_flag;
974

  
975
    cached_flag = getenv("RUBY_CACHED_LOAD_PATH");
976
    if (cached_flag != NULL) {
977
	cached_expanded_load_path = atoi(cached_flag);
978
    }
979

  
980
    // Do all the magick if user did not disable it
981
    // with RUBY_CACHED_LOAD_PATH=0 environment variable
982
    if (cached_expanded_load_path) {
983
	VALUE load_path_c = rb_singleton_class(load_path);
984

  
985
	for(name = load_path_reset_cache_methods; *name; name++ ) {
986
	    rb_define_method(load_path_c, *name, rb_load_path_reset_cache_method, -1);
987
	}
988

  
989
	for(name = load_path_apply_to_cache_methods; *name; name++ ) {
990
	    rb_define_method(load_path_c, *name, rb_load_path_apply_to_cache_method, -1);
991
	}
992

  
993
	for(name = load_path_apply_expanded_methods; *name; name++ ) {
994
	    rb_define_method(load_path_c, *name, rb_load_path_apply_expanded_method, -1);
995
	}
996

  
997
	rb_define_method(load_path_c, "concat", rb_load_path_concat, 1);
998
    }
999

  
1000
    rb_reset_expanded_cache();
1001

  
1002
    return load_path;
1003
}
1004

  
775 1005
void
776 1006
Init_load()
777 1007
{
......
784 1014
    rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
785 1015
    rb_alias_variable(rb_intern("$-I"), id_load_path);
786 1016
    rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
787
    vm->load_path = rb_ary_new();
1017
    vm->load_path = rb_load_path_init();
788 1018

  
789 1019
    rb_define_virtual_variable("$\"", get_loaded_features, 0);
790 1020
    rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
ruby.c
209 209
{
210 210
    const char sep = PATH_SEP_CHAR;
211 211
    const char *p, *s;
212
    VALUE load_path = GET_VM()->load_path;
213 212

  
214 213
    p = path;
215 214
    while (*p) {
......
217 216
	    p++;
218 217
	if (!*p) break;
219 218
	for (s = p; *s && *s != sep; s = CharNext(s));
220
	rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p)));
219
	rb_load_path_ary_push((*filter)(rubylib_mangled_path(p, s - p)));
221 220
	p = s;
222 221
    }
223 222
}
......
338 337
void
339 338
ruby_init_loadpath_safe(int safe_level)
340 339
{
341
    VALUE load_path;
342 340
    ID id_initial_load_path_mark;
343 341
    extern const char ruby_initial_load_paths[];
344 342
    const char *paths = ruby_initial_load_paths;
......
438 436
#define RUBY_RELATIVE(path, len) rubylib_mangled_path((path), (len))
439 437
#define PREFIX_PATH() RUBY_RELATIVE(exec_prefix, sizeof(exec_prefix)-1)
440 438
#endif
441
    load_path = GET_VM()->load_path;
442 439

  
443 440
    if (safe_level == 0) {
444 441
#ifdef MANGLED_PATH
......
452 449
	size_t len = strlen(paths);
453 450
	VALUE path = RUBY_RELATIVE(paths, len);
454 451
	rb_ivar_set(path, id_initial_load_path_mark, path);
455
	rb_ary_push(load_path, path);
452
	rb_load_path_ary_push(path);
456 453
	paths += len + 1;
457 454
    }
458 455

  
......
1349 1346
	for (i = 0; i < RARRAY_LEN(load_path); ++i) {
1350 1347
	    rb_enc_associate(RARRAY_PTR(load_path)[i], lenc);
1351 1348
	}
1349
	rb_reset_expanded_cache();
1352 1350
    }
1353 1351
    if (!(opt->disable & DISABLE_BIT(gems))) {
1354 1352
#if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS
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