diff --git a/file.c b/file.c
index fb62c51..8ab46d7 100644
--- a/file.c
+++ b/file.c
@@ -2821,6 +2821,16 @@ ntfs_tail(const char *path)
     buflen = RSTRING_LEN(result),\
     pend = p + buflen)
 
+#define EXPAND_PATH()\
+    if ( !(abs_mode & FEP_DIR_EXPANDED) ) { \
+	file_expand_path(dname, Qnil, abs_mode, result); \
+    } \
+    else { \
+	size_t dlen = RSTRING_LEN(dname); \
+	BUFCHECK(dlen > buflen); \
+	strncpy(buf, RSTRING_PTR(dname), dlen + 1); \
+    }
+
 VALUE
 rb_home_dir(const char *user, VALUE result)
 {
@@ -2865,6 +2875,8 @@ rb_home_dir(const char *user, VALUE result)
     return result;
 }
 
+#define FEP_FILE_ABSOLUTE 1
+#define FEP_DIR_EXPANDED 2
 static VALUE
 file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
 {
@@ -2877,7 +2889,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
     BUFINIT();
     tainted = OBJ_TAINTED(fname);
 
-    if (s[0] == '~' && abs_mode == 0) {      /* execute only if NOT absolute_path() */
+    if (s[0] == '~' && !(abs_mode & FEP_FILE_ABSOLUTE)) {      /* execute only if NOT absolute_path() */
 	long userlen = 0;
 	tainted = 1;
 	if (isdirsep(s[1]) || s[1] == '\0') {
@@ -2925,7 +2937,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
 	    /* specified drive, but not full path */
 	    int same = 0;
 	    if (!NIL_P(dname) && !not_same_drive(dname, s[0])) {
-		file_expand_path(dname, Qnil, abs_mode, result);
+		EXPAND_PATH();
 		BUFINIT();
 		if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) {
 		    /* ok, same drive */
@@ -2951,7 +2963,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
 #endif
     else if (!rb_is_absolute_path(s)) {
 	if (!NIL_P(dname)) {
-	    file_expand_path(dname, Qnil, abs_mode, result);
+	    EXPAND_PATH();
 	    BUFINIT();
 	    rb_enc_associate(result, rb_enc_check(result, fname));
 	}
@@ -3235,7 +3247,7 @@ VALUE
 rb_file_absolute_path(VALUE fname, VALUE dname)
 {
     check_expand_path_args(fname, dname);
-    return file_expand_path(fname, dname, 1, EXPAND_PATH_BUFFER());
+    return file_expand_path(fname, dname, FEP_FILE_ABSOLUTE, EXPAND_PATH_BUFFER());
 }
 
 /*
@@ -5109,13 +5121,23 @@ rb_find_file_ext(VALUE *filep, const char *const *ext)
     return rb_find_file_ext_safe(filep, ext, rb_safe_level());
 }
 
+#define GET_LOAD_PATH() \
+    if (cached_expanded_load_path) { \
+	RB_GC_GUARD(load_path) = rb_get_expanded_load_path(); \
+	dirs_mode = FEP_DIR_EXPANDED; \
+    } \
+    else { \
+	RB_GC_GUARD(load_path) = rb_get_load_path(); \
+	dirs_mode = 0; \
+    }
+
 int
 rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
 {
     const char *f = StringValueCStr(*filep);
     VALUE fname = *filep, load_path, tmp;
     long i, j, fnlen;
-    int expanded = 0;
+    int expanded = 0, dirs_mode;
 
     if (!ext[0]) return 0;
 
@@ -5150,7 +5172,7 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
 	rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
     }
 
-    RB_GC_GUARD(load_path) = rb_get_load_path();
+    GET_LOAD_PATH();
     if (!load_path) return 0;
 
     fname = rb_str_dup(*filep);
@@ -5164,7 +5186,7 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
 
 	    RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
 	    if (RSTRING_LEN(str) == 0) continue;
-	    file_expand_path(fname, str, 0, tmp);
+	    file_expand_path(fname, str, dirs_mode, tmp);
 	    if (file_load_ok(RSTRING_PTR(tmp))) {
 		*filep = copy_path_class(tmp, *filep);
 		return (int)(j+1);
@@ -5188,7 +5210,7 @@ rb_find_file_safe(VALUE path, int safe_level)
 {
     VALUE tmp, load_path;
     const char *f = StringValueCStr(path);
-    int expanded = 0;
+    int expanded = 0, dirs_mode;
 
     if (f[0] == '~') {
 	tmp = file_expand_path_1(path);
@@ -5214,7 +5236,7 @@ rb_find_file_safe(VALUE path, int safe_level)
 	rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
     }
 
-    RB_GC_GUARD(load_path) = rb_get_load_path();
+    GET_LOAD_PATH();
     if (load_path) {
 	long i;
 
@@ -5223,7 +5245,7 @@ rb_find_file_safe(VALUE path, int safe_level)
 	    VALUE str = RARRAY_PTR(load_path)[i];
 	    RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
 	    if (RSTRING_LEN(str) > 0) {
-		file_expand_path(path, str, 0, tmp);
+		file_expand_path(path, str, dirs_mode, tmp);
 		f = RSTRING_PTR(tmp);
 		if (file_load_ok(f)) goto found;
 	    }
diff --git a/internal.h b/internal.h
index b45b401..9f1b465 100644
--- a/internal.h
+++ b/internal.h
@@ -109,6 +109,8 @@ VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
 
 /* load.c */
 VALUE rb_get_load_path(void);
+VALUE rb_get_expanded_load_path(void);
+RUBY_EXTERN int cached_expanded_load_path;
 
 /* math.c */
 VALUE rb_math_atan2(VALUE, VALUE);
diff --git a/load.c b/load.c
index 9a31460..a89ac52 100644
--- a/load.c
+++ b/load.c
@@ -36,7 +36,7 @@ rb_get_load_path(void)
 
 static VALUE rb_checked_expanded_cache();
 static void rb_set_expanded_cache(VALUE);
-static int cached_expanded_load_path = 1;
+int cached_expanded_load_path = 1;
 
 VALUE
 rb_get_expanded_load_path(void)
@@ -47,6 +47,8 @@ rb_get_expanded_load_path(void)
 	VALUE load_path = rb_get_load_path();
 	long i;
 
+	if (!load_path) return 0;
+
 	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);
