diff --git a/.gitignore b/.gitignore
index 57557c9..7955376 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,3 +129,4 @@ y.tab.c
 
 # /win32/
 /win32/*.ico
+ext/win32ole/.document
diff --git a/array.c b/array.c
index 9664626..70a5fb5 100644
--- a/array.c
+++ b/array.c
@@ -305,7 +305,7 @@ ary_alloc(VALUE klass)
     return (VALUE)ary;
 }
 
-static VALUE
+VALUE // TODO: Removed the static declaration off this, figure out if that is OK
 ary_new(VALUE klass, long capa)
 {
     VALUE ary;
diff --git a/enumerator.c b/enumerator.c
index 7bb5ecd..b8ce698 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -1171,6 +1171,4 @@ Init_Enumerator(void)
     id_rewind = rb_intern("rewind");
     id_each = rb_intern("each");
     sym_each = ID2SYM(id_each);
-
-    rb_provide("enumerator.so");	/* for backward compatibility */
 }
diff --git a/file.c b/file.c
index 3746009..8fcf0fe 100644
--- a/file.c
+++ b/file.c
@@ -1270,7 +1270,7 @@ rb_file_chardev_p(VALUE obj, VALUE fname)
  * Return true if the named file exists.
  */
 
-static VALUE
+VALUE // TODO: Mark this as static again
 rb_file_exist_p(VALUE obj, VALUE fname)
 {
     struct stat st;
diff --git a/lib/enumerator.rb b/lib/enumerator.rb
new file mode 100644
index 0000000..b028c83
--- /dev/null
+++ b/lib/enumerator.rb
@@ -0,0 +1,3 @@
+# This class is now defined entirely in enumerator.c and is always available.
+# This file needs to remain here for backwards compatibility, so that `require
+# "enumerator"` will not raise an exception.
diff --git a/load.c b/load.c
index 547c115..6a19093 100644
--- a/load.c
+++ b/load.c
@@ -18,8 +18,50 @@ VALUE ruby_dln_librefs;
 #endif
 
 
+VALUE rb_f_require(VALUE, VALUE);
+VALUE rb_f_require_relative(VALUE, VALUE);
+static VALUE rb_f_load(int, VALUE *);
+VALUE rb_require_safe(VALUE, int);
+
+static int rb_file_has_been_required(VALUE);
+static int rb_file_is_being_required(VALUE);
+static int rb_file_is_ruby(VALUE);
+static st_table * get_loaded_features_hash(void);
+static void rb_load_internal(VALUE, int);
+static char * load_lock(const char *);
+static void load_unlock(const char *, int);
+static void load_failed(VALUE fname);
+
+void rb_provide(const char *feature);
+static void rb_provide_feature(VALUE);
+
+/* 
+ * TODO: These functions are all conceptually related, and should be extracted
+ * into a separate file.
+ */
+static VALUE rb_locate_file(VALUE);
+static VALUE rb_locate_file_absolute(VALUE);
+static VALUE rb_locate_file_relative(VALUE);
+static VALUE rb_locate_file_in_load_path(VALUE);
+static VALUE rb_locate_file_with_extensions(VALUE);
+static int rb_path_is_absolute(VALUE);
+static int rb_path_is_relative(VALUE);
+VALUE rb_get_expanded_load_path();
+
+/* 
+ * TODO: These functions are all conceptually related, and should be extracted
+ * into a separate file.
+ */
+static VALUE rb_cLoadedFeaturesProxy;
+static void rb_rehash_loaded_features();
+static VALUE rb_loaded_features_hook(int, VALUE*, VALUE);
+static void define_loaded_features_proxy();
+
+VALUE ary_new(VALUE, long); // array.c
+
 static const char *const loadable_ext[] = {
-    ".rb", DLEXT,
+    ".rb", 
+    DLEXT,
 #ifdef DLEXT2
     DLEXT2,
 #endif
@@ -33,6 +75,32 @@ rb_get_load_path(void)
     return load_path;
 }
 
+static st_table *
+get_loaded_features_hash(void)
+{
+    st_table* loaded_features_hash;
+    loaded_features_hash = GET_VM()->loaded_features_hash;
+
+    if (!loaded_features_hash) {
+      GET_VM()->loaded_features_hash = loaded_features_hash = st_init_strcasetable();
+    }
+
+    return loaded_features_hash;
+}
+
+static st_table *
+get_filename_expansion_hash(void)
+{
+    st_table* filename_expansion_hash;
+    filename_expansion_hash = GET_VM()->filename_expansion_hash;
+
+    if (!filename_expansion_hash) {
+      GET_VM()->filename_expansion_hash = filename_expansion_hash = st_init_strcasetable();
+    }
+
+    return filename_expansion_hash;
+}
+
 VALUE
 rb_get_expanded_load_path(void)
 {
@@ -68,185 +136,32 @@ get_loading_table(void)
     return GET_VM()->loading_table;
 }
 
-static VALUE
-loaded_feature_path(const char *name, long vlen, const char *feature, long len,
-		    int type, VALUE load_path)
-{
-    long i;
-
-    for (i = 0; i < RARRAY_LEN(load_path); ++i) {
-	VALUE p = RARRAY_PTR(load_path)[i];
-	const char *s = StringValuePtr(p);
-	long n = RSTRING_LEN(p);
-
-	if (vlen < n + len + 1) continue;
-	if (n && (strncmp(name, s, n) || name[n] != '/')) continue;
-	if (strncmp(name + n + 1, feature, len)) continue;
-	if (name[n+len+1] && name[n+len+1] != '.') continue;
-	switch (type) {
-	  case 's':
-	    if (IS_DLEXT(&name[n+len+1])) return p;
-	    break;
-	  case 'r':
-	    if (IS_RBEXT(&name[n+len+1])) return p;
-	    break;
-	  default:
-	    return p;
-	}
-    }
-    return 0;
-}
-
-struct loaded_feature_searching {
-    const char *name;
-    long len;
-    int type;
-    VALUE load_path;
-    const char *result;
-};
-
-static int
-loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
-{
-    const char *s = (const char *)v;
-    struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
-    VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
-				  fp->type, fp->load_path);
-    if (!p) return ST_CONTINUE;
-    fp->result = s;
-    return ST_STOP;
-}
-
-static int
-rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
-{
-    VALUE v, features, p, load_path = 0;
-    const char *f, *e;
-    long i, len, elen, n;
-    st_table *loading_tbl;
-    st_data_t data;
-    int type;
-
-    if (fn) *fn = 0;
-    if (ext) {
-	elen = strlen(ext);
-	len = strlen(feature) - elen;
-	type = rb ? 'r' : 's';
-    }
-    else {
-	len = strlen(feature);
-	elen = 0;
-	type = 0;
-    }
-    features = get_loaded_features();
-    for (i = 0; i < RARRAY_LEN(features); ++i) {
-	v = RARRAY_PTR(features)[i];
-	f = StringValuePtr(v);
-	if ((n = RSTRING_LEN(v)) < len) continue;
-	if (strncmp(f, feature, len) != 0) {
-	    if (expanded) continue;
-	    if (!load_path) load_path = rb_get_expanded_load_path();
-	    if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
-		continue;
-	    expanded = 1;
-	    f += RSTRING_LEN(p) + 1;
-	}
-	if (!*(e = f + len)) {
-	    if (ext) continue;
-	    return 'u';
-	}
-	if (*e != '.') continue;
-	if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
-	    return 's';
-	}
-	if ((rb || !ext) && (IS_RBEXT(e))) {
-	    return 'r';
-	}
-    }
-    loading_tbl = get_loading_table();
-    if (loading_tbl) {
-	f = 0;
-	if (!expanded) {
-	    struct loaded_feature_searching fs;
-	    fs.name = feature;
-	    fs.len = len;
-	    fs.type = type;
-	    fs.load_path = load_path ? load_path : rb_get_load_path();
-	    fs.result = 0;
-	    st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
-	    if ((f = fs.result) != 0) {
-		if (fn) *fn = f;
-		goto loading;
-	    }
-	}
-	if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
-	    if (fn) *fn = (const char*)data;
-	  loading:
-	    if (!ext) return 'u';
-	    return !IS_RBEXT(ext) ? 's' : 'r';
-	}
-	else {
-	    VALUE bufstr;
-	    char *buf;
-
-	    if (ext && *ext) return 0;
-	    bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
-	    buf = RSTRING_PTR(bufstr);
-	    MEMCPY(buf, feature, char, len);
-	    for (i = 0; (e = loadable_ext[i]) != 0; i++) {
-		strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
-		if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
-		    rb_str_resize(bufstr, 0);
-		    if (fn) *fn = (const char*)data;
-		    return i ? 's' : 'r';
-		}
-	    }
-	    rb_str_resize(bufstr, 0);
-	}
-    }
-    return 0;
-}
-
 int
 rb_provided(const char *feature)
 {
     return rb_feature_provided(feature, 0);
 }
 
-int
-rb_feature_provided(const char *feature, const char **loading)
+
+/* Mark the given feature as loaded, after it has been evaluated. */
+	static void
+rb_provide_feature(VALUE feature)
 {
-    const char *ext = strrchr(feature, '.');
-    volatile VALUE fullpath = 0;
+	int frozen = 0;
+	st_table* loaded_features_hash;
 
-    if (*feature == '.' &&
-	(feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
-	fullpath = rb_file_expand_path(rb_str_new2(feature), Qnil);
-	feature = RSTRING_PTR(fullpath);
-    }
-    if (ext && !strchr(ext, '/')) {
-	if (IS_RBEXT(ext)) {
-	    if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
-	    return FALSE;
+	if (OBJ_FROZEN(get_loaded_features())) {
+		rb_raise(rb_eRuntimeError,
+				"$LOADED_FEATURES is frozen; cannot append feature");
 	}
-	else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
-	    if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
-	    return FALSE;
-	}
-    }
-    if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
-	return TRUE;
-    return FALSE;
-}
 
-static void
-rb_provide_feature(VALUE feature)
-{
-    if (OBJ_FROZEN(get_loaded_features())) {
-	rb_raise(rb_eRuntimeError,
-		 "$LOADED_FEATURES is frozen; cannot append feature");
-    }
-    rb_ary_push(get_loaded_features(), feature);
+	loaded_features_hash = get_loaded_features_hash();
+	st_insert(
+			loaded_features_hash,
+			(st_data_t)ruby_strdup(RSTRING_PTR(feature)),
+			(st_data_t)rb_barrier_new());
+
+	rb_ary_push(get_loaded_features(), feature);
 }
 
 void
@@ -418,34 +333,6 @@ load_unlock(const char *ftptr, int done)
 
 
 /*
- *  call-seq:
- *     require(string)    -> true or false
- *
- *  Ruby tries to load the library named _string_, returning
- *  +true+ if successful. If the filename does not resolve to
- *  an absolute path, it will be searched for in the directories listed
- *  in $:. If the file has the extension ``.rb'', it is
- *  loaded as a source file; if the extension is ``.so'', ``.o'', or
- *  ``.dll'', or whatever the default shared library extension is on
- *  the current platform, Ruby loads the shared library as a Ruby
- *  extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
- *  to the name. The name of the loaded feature is added to the array in
- *  $". A feature will not be loaded if its name already
- *  appears in $". The file name is converted to an absolute
- *  path, so ``require 'a'; require './a''' will not load
- *  a.rb twice.
- *
- *     require "my-library.rb"
- *     require "db-driver"
- */
-
-VALUE
-rb_f_require(VALUE obj, VALUE fname)
-{
-    return rb_require_safe(fname, rb_safe_level());
-}
-
-/*
  * call-seq:
  *   require_relative(string) -> true or false
  *
@@ -465,92 +352,6 @@ rb_f_require_relative(VALUE obj, VALUE fname)
     return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
 }
 
-static int
-search_required(VALUE fname, volatile VALUE *path, int safe_level)
-{
-    VALUE tmp;
-    char *ext, *ftptr;
-    int type, ft = 0;
-    const char *loading;
-
-    *path = 0;
-    ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
-    if (ext && !strchr(ext, '/')) {
-	if (IS_RBEXT(ext)) {
-	    if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
-		if (loading) *path = rb_str_new2(loading);
-		return 'r';
-	    }
-	    if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
-		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
-		    *path = tmp;
-		return 'r';
-	    }
-	    return 0;
-	}
-	else if (IS_SOEXT(ext)) {
-	    if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
-		if (loading) *path = rb_str_new2(loading);
-		return 's';
-	    }
-	    tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
-#ifdef DLEXT2
-	    OBJ_FREEZE(tmp);
-	    if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
-		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
-		    *path = tmp;
-		return 's';
-	    }
-#else
-	    rb_str_cat2(tmp, DLEXT);
-	    OBJ_FREEZE(tmp);
-	    if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
-		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
-		    *path = tmp;
-		return 's';
-	    }
-#endif
-	}
-	else if (IS_DLEXT(ext)) {
-	    if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
-		if (loading) *path = rb_str_new2(loading);
-		return 's';
-	    }
-	    if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
-		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
-		    *path = tmp;
-		return 's';
-	    }
-	}
-    }
-    else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
-	if (loading) *path = rb_str_new2(loading);
-	return 'r';
-    }
-    tmp = fname;
-    type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
-    switch (type) {
-      case 0:
-	if (ft)
-	    break;
-	ftptr = RSTRING_PTR(tmp);
-	return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
-
-      default:
-	if (ft)
-	    break;
-      case 1:
-	ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-	if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
-	    break;
-	*path = tmp;
-    }
-    return type ? 's' : 'r';
-}
 
 static void
 load_failed(VALUE fname)
@@ -568,67 +369,6 @@ load_ext(VALUE path)
 }
 
 VALUE
-rb_require_safe(VALUE fname, int safe)
-{
-    volatile VALUE result = Qnil;
-    rb_thread_t *th = GET_THREAD();
-    volatile VALUE errinfo = th->errinfo;
-    int state;
-    struct {
-	int safe;
-    } volatile saved;
-    char *volatile ftptr = 0;
-
-    PUSH_TAG();
-    saved.safe = rb_safe_level();
-    if ((state = EXEC_TAG()) == 0) {
-	VALUE path;
-	long handle;
-	int found;
-
-	rb_set_safe_level_force(safe);
-	FilePathValue(fname);
-	rb_set_safe_level_force(0);
-	found = search_required(fname, &path, safe);
-	if (found) {
-	    if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
-		result = Qfalse;
-	    }
-	    else {
-		switch (found) {
-		  case 'r':
-		    rb_load_internal(path, 0);
-		    break;
-
-		  case 's':
-		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
-						    path, 0, path);
-		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
-		    break;
-		}
-		rb_provide_feature(path);
-		result = Qtrue;
-	    }
-	}
-    }
-    POP_TAG();
-    load_unlock(ftptr, !state);
-
-    rb_set_safe_level_force(saved.safe);
-    if (state) {
-	JUMP_TAG(state);
-    }
-
-    if (NIL_P(result)) {
-	load_failed(fname);
-    }
-
-    th->errinfo = errinfo;
-
-    return result;
-}
-
-VALUE
 rb_require(const char *fname)
 {
     VALUE fn = rb_str_new2(fname);
@@ -741,11 +481,428 @@ rb_f_autoload_p(VALUE obj, VALUE sym)
     return rb_mod_autoload_p(klass, sym);
 }
 
+VALUE
+rb_file_exist_p(VALUE obj, VALUE path);
+
+static int
+rb_feature_exists(VALUE expanded_path)
+{
+  return rb_funcall(rb_cFile, rb_intern("file?"), 1, expanded_path) == Qtrue;
+}
+
+const char *available_extensions[] = {
+  ".rb",
+  DLEXT,
+#ifdef DLEXT2
+  DLEXT2,
+#endif
+  ""
+};
+
+#ifdef DLEXT2
+VALUE available_ext_rb_str[4];
+#else
+VALUE available_ext_rb_str[3];
+#endif
+
+const char *alternate_dl_extensions[] = {
+  DLEXT,
+#ifdef DLEXT2
+  DLEXT2
+#endif
+};
+
+#define CHAR_ARRAY_LEN(array) sizeof(array) / sizeof(char*)
+#define VALUE_ARRAY_LEN(array) sizeof(array) / sizeof(VALUE)
+
+static VALUE
+rb_locate_file_with_extensions(VALUE base_file_name) {
+	unsigned int j;
+	VALUE file_name_with_extension;
+	VALUE extension;
+	VALUE directory, basename;
+
+	extension = rb_funcall(rb_cFile, rb_intern("extname"), 1, base_file_name);
+
+	if (RSTRING_LEN(extension) == 0) {
+		for (j = 0; j < VALUE_ARRAY_LEN(available_ext_rb_str); ++j) {
+			file_name_with_extension = rb_str_plus(
+					base_file_name,
+					available_ext_rb_str[j]);
+
+			if (rb_feature_exists(file_name_with_extension)) {
+				return file_name_with_extension;
+			}
+		}
+	} else {
+		if (rb_feature_exists(base_file_name)) {
+			return base_file_name;
+		} else {
+			for (j = 0; j < CHAR_ARRAY_LEN(alternate_dl_extensions); ++j) {
+				// Try loading the native DLEXT version of this platform.
+				// This allows 'pathname.so' to require 'pathname.bundle' on OSX
+				directory = rb_file_dirname(base_file_name);
+				basename  = rb_funcall(rb_cFile, rb_intern("basename"), 2, 
+						base_file_name, extension);
+				basename  = rb_str_cat2(basename, alternate_dl_extensions[j]);
+
+				file_name_with_extension = rb_funcall(rb_cFile, rb_intern("join"), 2, 
+						directory, basename);
+
+				if (rb_feature_exists(file_name_with_extension)) {
+					return file_name_with_extension;
+				}
+
+				// Also try loading 'dot.dot.bundle' for 'dot.dot'
+				file_name_with_extension = rb_str_plus(
+						base_file_name,
+						rb_str_new2(alternate_dl_extensions[j]));
+
+				if (rb_feature_exists(file_name_with_extension)) {
+					return file_name_with_extension;
+				}
+			}
+		}
+	}
+	return Qnil;
+}
+
+static VALUE
+rb_locate_file_absolute(VALUE fname)
+{
+	return rb_locate_file_with_extensions(fname);
+}
+
+static VALUE
+rb_locate_file_relative(VALUE fname)
+{
+	return rb_locate_file_with_extensions(rb_file_expand_path(fname, Qnil));
+}
+
+static VALUE
+rb_locate_file_in_load_path(VALUE path)
+{
+	long i, j;
+	VALUE load_path = rb_get_expanded_load_path();
+	VALUE expanded_file_name = Qnil;
+	VALUE base_file_name = Qnil;
+	VALUE sep = rb_str_new2("/");
+
+	for (i = 0; i < RARRAY_LEN(load_path); ++i) {
+		VALUE directory = RARRAY_PTR(load_path)[i];
+
+		base_file_name = rb_str_plus(directory, sep);
+		base_file_name = rb_str_concat(base_file_name, path);
+
+		expanded_file_name = rb_locate_file_with_extensions(base_file_name);
+
+		if (expanded_file_name != Qnil) {
+			return expanded_file_name;
+		}
+	}
+	return Qnil;
+}
+
+static int
+rb_path_is_relative(VALUE path)
+{
+	const char * path_ptr = RSTRING_PTR(path);
+	const char * current_directory = "./";
+	const char * parent_directory  = "../";
+
+	return (
+			strncmp(current_directory, path_ptr, 2) == 0 ||
+			strncmp(parent_directory,  path_ptr, 3) == 0
+		   );
+}
+
+static int
+rb_file_is_ruby(VALUE path)
+{
+	const char * ext;
+	ext = ruby_find_extname(RSTRING_PTR(path), 0);
+
+	return ext && IS_RBEXT(ext);
+}
+
+static int
+rb_path_is_absolute(VALUE path)
+{
+	// Delegate to file.c
+	return rb_is_absolute_path(RSTRING_PTR(path));
+}
+
+static int
+rb_file_has_been_required(VALUE expanded_path)
+{
+	st_data_t data;
+	st_data_t path_key = (st_data_t)RSTRING_PTR(expanded_path);
+	st_table *loaded_features_hash = get_loaded_features_hash();
+
+	return st_lookup(loaded_features_hash, path_key, &data);
+}
+
+static int
+rb_file_is_being_required(VALUE full_path) {
+	const char *ftptr = RSTRING_PTR(full_path);
+	st_data_t data;
+	st_table *loading_tbl = get_loading_table();
+
+	return (loading_tbl && st_lookup(loading_tbl, (st_data_t)ftptr, &data));
+}
+
+static VALUE
+rb_get_cached_expansion(VALUE filename) 
+{
+	st_data_t data;
+	st_data_t path_key = (st_data_t)RSTRING_PTR(filename);
+	st_table *filename_expansion_hash = get_filename_expansion_hash();
+
+	if (st_lookup(filename_expansion_hash, path_key, &data)) {
+		return (VALUE)data;
+	} else {
+		return Qnil;
+	};
+}
+
+static void
+rb_set_cached_expansion(VALUE filename, VALUE expanded)
+{
+	st_data_t data = (st_data_t)expanded;
+	st_data_t path_key = (st_data_t)RSTRING_PTR(filename);
+	st_table *filename_expansion_hash = get_filename_expansion_hash();
+
+	st_insert(filename_expansion_hash, path_key, data);
+}
+
+static VALUE
+rb_locate_file(VALUE filename)
+{
+	VALUE full_path = Qnil;
+
+	full_path = rb_get_cached_expansion(filename);
+
+	if (full_path != Qnil)
+		return full_path;
+
+	if (rb_path_is_relative(filename)) {
+		full_path = rb_locate_file_relative(filename);
+	} else if (rb_path_is_absolute(filename)) {
+		full_path = rb_locate_file_absolute(filename);
+	} else {
+		full_path = rb_locate_file_in_load_path(filename);
+	}
+
+	if (full_path != Qnil)
+		rb_set_cached_expansion(filename, full_path);
+
+	return full_path;
+}
+
+/* 
+ * returns the path loaded, or nil if the file was already loaded. Raises
+ * LoadError if a file cannot be found. 
+ */
+VALUE
+rb_require_safe(VALUE fname, int safe)
+{
+	VALUE path = Qnil;
+	volatile VALUE result = Qnil;
+	rb_thread_t *th = GET_THREAD();
+	volatile VALUE errinfo = th->errinfo;
+	int state;
+	struct {
+		int safe;
+	} volatile saved;
+	char *volatile ftptr = 0;
+
+	PUSH_TAG();
+	saved.safe = rb_safe_level();
+	if ((state = EXEC_TAG()) == 0) {
+		long handle;
+		int found;
+
+		rb_set_safe_level_force(safe);
+		FilePathValue(fname);
+		rb_set_safe_level_force(0);
+
+		path = rb_locate_file(fname);
+
+		if (safe >= 1 && OBJ_TAINTED(path)) {
+			rb_raise(rb_eSecurityError, "Loading from unsafe file %s", RSTRING_PTR(path));
+		}
+
+		result = Qfalse;
+		if (path == Qnil) {
+			load_failed(fname);
+		} else {
+			if (ftptr = load_lock(RSTRING_PTR(path))) { // Allows circular requires to work
+				if (!rb_file_has_been_required(path)) {
+					if (rb_file_is_ruby(path)) {
+						rb_load_internal(path, 0);
+					} else {
+						handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
+								path, 0, path);
+						rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
+					}
+					rb_provide_feature(path);
+					result = Qtrue;
+				}
+			}
+		}
+	}
+	POP_TAG();
+	load_unlock(ftptr, !state);
+
+	rb_set_safe_level_force(saved.safe);
+	if (state) {
+		JUMP_TAG(state);
+	}
+
+	if (NIL_P(result)) {
+		load_failed(fname);
+	}
+
+	th->errinfo = errinfo;
+
+	if (result == Qtrue) {
+		return path;
+	} else {
+		return Qnil;
+	}
+}
+
+/*
+ *  call-seq:
+ *     require(string)    -> true or false
+ *
+ *  Ruby tries to load the library named _string_, returning
+ *  +true+ if successful. If the filename does not resolve to
+ *  an absolute path, it will be searched for in the directories listed
+ *  in $:. If the file has the extension ``.rb'', it is
+ *  loaded as a source file; if the extension is ``.so'', ``.o'', or
+ *  ``.dll'', or whatever the default shared library extension is on
+ *  the current platform, Ruby loads the shared library as a Ruby
+ *  extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
+ *  to the name. The name of the loaded feature is added to the array in
+ *  $". A feature will not be loaded if its name already
+ *  appears in $". The file name is converted to an absolute
+ *  path, so ``require 'a'; require './a''' will not load
+ *  a.rb twice.
+ *
+ *     require "my-library.rb"
+ *     require "db-driver"
+ */
+VALUE
+rb_f_require(VALUE obj, VALUE fname)
+{
+    return rb_require_safe(fname, rb_safe_level()) == Qnil ? Qfalse : Qtrue;
+}
+
+static void
+rb_rehash_loaded_features()
+{
+  int i;
+  VALUE features;
+  VALUE feature;
+
+  st_table* loaded_features_hash = get_loaded_features_hash();
+
+  st_clear(loaded_features_hash);
+
+  features = get_loaded_features();
+
+  for (i = 0; i < RARRAY_LEN(features); ++i) {
+    feature = RARRAY_PTR(features)[i];
+    st_insert(
+      loaded_features_hash,
+      (st_data_t)ruby_strdup(RSTRING_PTR(feature)),
+      (st_data_t)rb_barrier_new());
+  }
+}
+
+static void
+rb_clear_cached_expansions()
+{
+  st_table* filename_expansion_hash = get_filename_expansion_hash();
+  st_clear(filename_expansion_hash);
+}
+
+static VALUE  
+rb_loaded_features_hook(int argc, VALUE *argv, VALUE self)  
+{ 
+	VALUE ret;
+	ret = rb_call_super(argc, argv);
+	rb_rehash_loaded_features();
+	rb_clear_cached_expansions();
+	return ret;
+}
+
+/*
+ * $LOADED_FEATURES is exposed publically as an array, but under the covers
+ * we also store this data in a hash for fast lookups. So that we can rebuild
+ * the hash whenever $LOADED_FEATURES is changed, we wrap the Array class
+ * in a proxy that intercepts all data-modifying methods and rebuilds the
+ * hash.
+ *
+ * Note that the list of intercepted methods is currently non-comprehensive
+ * --- it only covers modifications made by the ruby and rubyspec test suites.
+ */
+static void 
+define_loaded_features_proxy()
+{
+	const char* methods_to_hook[] = {"push", "clear", "replace", "delete"};
+	unsigned int i;
+
+	rb_cLoadedFeaturesProxy = rb_define_class("LoadedFeaturesProxy", rb_cArray); 
+	for (i = 0; i < CHAR_ARRAY_LEN(methods_to_hook); ++i) {
+		rb_define_method(
+				rb_cLoadedFeaturesProxy,
+				methods_to_hook[i],
+				rb_loaded_features_hook,
+				-1);
+	}
+}
+
+
+/* Should return true if the file has or is being loaded, but should 
+ * not actually load the file.
+ */
+int
+rb_feature_provided_2(VALUE fname)
+{
+	VALUE full_path = rb_locate_file(fname);
+
+	if (
+		full_path != Qnil && 
+		(
+			rb_file_has_been_required(full_path) || 
+			rb_file_is_being_required(full_path)
+		)
+	) {
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+/*
+ * Deprecated, use rb_feature_provided_2
+ */
+int
+rb_feature_provided(const char *feature, const char **loading)
+{
+    VALUE fname = rb_str_new2(feature);
+	rb_feature_provided_2(fname);
+}
+
+
 void
 Init_load()
 {
 #undef rb_intern
 #define rb_intern(str) rb_intern2((str), strlen(str))
+	unsigned int j;
     rb_vm_t *vm = GET_VM();
     static const char var_load_path[] = "$:";
     ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
@@ -757,7 +914,10 @@ Init_load()
 
     rb_define_virtual_variable("$\"", get_loaded_features, 0);
     rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
-    vm->loaded_features = rb_ary_new();
+
+    define_loaded_features_proxy();
+
+    vm->loaded_features = ary_new(rb_cLoadedFeaturesProxy, RARRAY_EMBED_LEN_MAX);
 
     rb_define_global_function("load", rb_f_load, -1);
     rb_define_global_function("require", rb_f_require, 1);
@@ -769,4 +929,9 @@ Init_load()
 
     ruby_dln_librefs = rb_ary_new();
     rb_gc_register_mark_object(ruby_dln_librefs);
+
+	for (j = 0; j < CHAR_ARRAY_LEN(available_extensions); ++j) {
+		available_ext_rb_str[j] = rb_str_new2(available_extensions[j]);
+		rb_gc_register_mark_object(available_ext_rb_str[j]);
+	}
 }
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 96b1551..9f9444c 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -339,4 +339,50 @@ class TestRequire < Test::Unit::TestCase
                       [], /\$LOADED_FEATURES is frozen; cannot append feature \(RuntimeError\)$/,
                       bug3756)
   end
+
+  def test_case_insensitive
+    load_path = $:.dup
+    loaded = $".dup
+    path = File.expand_path(__FILE__)
+    $:.unshift(File.dirname(path))
+    $".push(path) unless $".include?(path)
+    bug4255 = '[ruby-core:34297]'
+    assert_equal(false, $bug4255 ||= false, bug4255)
+    $bug4255 = true
+    f = File.basename(__FILE__, ".*").upcase
+    assert_equal(false, require(f))
+  ensure
+    $:.replace(load_path)
+    $".replace(loaded)
+  end if File.identical?(__FILE__, __FILE__.upcase)
+
+  def test_feature_is_reloaded_from_new_load_path_entry
+    # This is a bit of a weird test, but it is needed to ensure that some
+    # caching optimizations are working correctly.
+    load_path      = $:.dup
+    loaded         = $".dup
+    initial_length = loaded.length
+
+    Dir.mktmpdir do |tmp|
+      Dir.chdir(tmp) do
+        Dir.mkdir "a"
+        Dir.mkdir "b"
+        File.open("a/test.rb", "w") {|f| f.puts '' }
+        File.open("b/test.rb", "w") {|f| f.puts '' }
+
+        $".clear
+        $:.unshift(File.join(tmp, "b"))
+        require 'test.rb'
+        assert $"[0].include?('b/test.rb')
+
+        $".clear
+        $:.unshift(File.join(tmp, "a"))
+        require 'test.rb'
+        assert $"[0].include?('a/test.rb')
+      end
+    end
+  ensure
+    $:.replace(load_path)
+    $".replace(loaded)
+  end
 end
diff --git a/variable.c b/variable.c
index 426d58f..551a7d5 100644
--- a/variable.c
+++ b/variable.c
@@ -1489,10 +1489,9 @@ autoload_delete(VALUE mod, ID id)
 }
 
 static VALUE
-autoload_provided(VALUE arg)
+autoload_provided(VALUE fname)
 {
-    const char **p = (const char **)arg;
-    return rb_feature_provided(*p, p);
+    return rb_feature_provided_2(fname);
 }
 
 static VALUE
@@ -1525,7 +1524,7 @@ autoload_node(VALUE mod, ID id, const char **loadingpath)
     loading = RSTRING_PTR(file);
     safe = rb_safe_level();
     rb_set_safe_level_force(0);
-    if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
+    if (!rb_ensure(autoload_provided, (VALUE)file, reset_safe, (VALUE)safe)) {
 	return load;
     }
     if (loadingpath && loading) {
diff --git a/vm.c b/vm.c
index bddb4dd..a96b006 100644
--- a/vm.c
+++ b/vm.c
@@ -1527,6 +1527,14 @@ rb_vm_mark(void *ptr)
 	    rb_mark_tbl(vm->loading_table);
 	}
 
+	if (vm->loaded_features_hash) {
+	    rb_mark_tbl(vm->loaded_features_hash);
+	}
+
+	if (vm->filename_expansion_hash) {
+	    rb_mark_tbl(vm->filename_expansion_hash);
+	}
+
 	mark_event_hooks(vm->event_hooks);
 
 	for (i = 0; i < RUBY_NSIG; i++) {
diff --git a/vm_core.h b/vm_core.h
index e302e62..d5f5fb7 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -324,6 +324,9 @@ typedef struct rb_vm_struct {
      * objects so do *NOT* mark this when you GC.
      */
     struct RArray at_exit;
+
+    struct st_table *loaded_features_hash;
+    struct st_table *filename_expansion_hash;
 } rb_vm_t;
 
 typedef struct {