diff --git a/load.c b/load.c index f31b7aeaca961b..2ddeb11c8ea00d 100644 --- a/load.c +++ b/load.c @@ -944,6 +944,7 @@ rb_require_safe(VALUE fname, int safe) { volatile VALUE result = Qnil; rb_thread_t *th = GET_THREAD(); + rb_vm_t *vm = GET_VM(); volatile VALUE errinfo = th->errinfo; int state; struct { @@ -951,6 +952,9 @@ rb_require_safe(VALUE fname, int safe) } volatile saved; char *volatile ftptr = 0; + if (strncmp(StringValuePtr(fname), "enumerator", 11) == 0) + return Qfalse; + if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname), rb_sourcefile(), @@ -960,9 +964,11 @@ rb_require_safe(VALUE fname, int safe) PUSH_TAG(); saved.safe = rb_safe_level(); if ((state = EXEC_TAG()) == 0) { - VALUE path; + VALUE ipath, path = 0; long handle; int found; + st_data_t key, val; + char *vals; rb_set_safe_level_force(safe); FilePathValue(fname); @@ -974,8 +980,36 @@ rb_require_safe(VALUE fname, int safe) rb_sourceline()); } - path = rb_str_encode_ospath(fname); - found = search_required(path, &path, safe); + ipath = rb_str_encode_ospath(fname); + if (vm->require_cache.read && RSTRING_PTR(ipath)[0] != '/') { + key = (st_data_t)RSTRING_PTR(ipath); + if (st_lookup(vm->require_cache.tbl, key, &val)) { + vals = (char *)val; + found = vals[0]; + if (found) { + /*fprintf(stderr, "FOUND '%s' => '%s'\n", (char *)key, vals);*/ + path = rb_str_new_cstr(vals+1); + vals[1] = 0; + } + } else { + found = search_required(ipath, &path, safe); + /*if (found && path) + fprintf(stderr, "MISSING '%s' => '%s'\n", RSTRING_PTR(ipath), RSTRING_PTR(path));*/ + } + } else { + found = search_required(ipath, &path, safe); + /*if (found && path) + fprintf(stderr, "SEARCHING '%s' found '%s'\n", RSTRING_PTR(ipath), RSTRING_PTR(path));*/ + } + if (vm->require_cache.write && RSTRING_PTR(ipath)[0] != '/' && (!found || (found && path))) { + /*fprintf(stderr, "WRITING '%s' => '%s'\n", RSTRING_PTR(ipath), found ? RSTRING_PTR(path) : "");*/ + fprintf(vm->require_cache.out, "%s\n", RSTRING_PTR(ipath)); + if (found) + fprintf(vm->require_cache.out, "%c%s\n", found, RSTRING_PTR(path)); + else + fprintf(vm->require_cache.out, "%s\n", ""); + fsync(fileno(vm->require_cache.out)); + } if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) { RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname), @@ -1154,6 +1188,35 @@ rb_f_autoload_p(VALUE obj, VALUE sym) return rb_mod_autoload_p(klass, sym); } +void +require_cache_setup() +{ + rb_vm_t *vm = GET_VM(); + FILE *file; + char *env, line1[PATH_MAX+3], line2[PATH_MAX+3]; + + if ((env = getenv("REQUIRE_CACHE_WRITE"))) { + unsetenv("REQUIRE_CACHE_WRITE", ""); + vm->require_cache.write = 1; + vm->require_cache.out = fopen(env, "w"); + } else if ((env = getenv("REQUIRE_CACHE_READ"))) { + file = fopen(env, "r"); + if (!file) return; + + vm->require_cache.read = 1; + vm->require_cache.tbl = st_init_strtable(); + while (1) { + if (!fgets(line1, PATH_MAX+2, file)) break; + if (!fgets(line2, PATH_MAX+2, file)) break; + line1[strlen(line1)-1] = 0; + line2[strlen(line2)-1] = 0; + /*fprintf(stderr, "INSERTING '%s' => '%s'\n", line1, line2);*/ + st_insert(vm->require_cache.tbl, (st_data_t)ruby_strdup(line1), (st_data_t)ruby_strdup(line2)); + } + fclose(file); + } +} + void Init_load() { @@ -1187,4 +1250,6 @@ Init_load() ruby_dln_librefs = rb_ary_tmp_new(0); rb_gc_register_mark_object(ruby_dln_librefs); + + require_cache_setup(); } diff --git a/vm.c b/vm.c index 212f7b01401f68..cb8456bbf96c5a 100644 --- a/vm.c +++ b/vm.c @@ -1823,6 +1823,9 @@ ruby_vm_destruct(rb_vm_t *vm) #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE struct rb_objspace *objspace = vm->objspace; #endif + if (vm->require_cache.write) + fclose(vm->require_cache.out); + rb_gc_force_recycle(vm->self); vm->main_thread = 0; if (th) { diff --git a/vm_core.h b/vm_core.h index 73127e65eab41d..a19bba74e3f627 100644 --- a/vm_core.h +++ b/vm_core.h @@ -377,6 +377,12 @@ typedef struct rb_vm_struct { VALUE loaded_features_snapshot; struct st_table *loaded_features_index; struct st_table *loading_table; + struct { + unsigned int read:1; + struct st_table *tbl; + unsigned int write:1; + FILE *out; + } require_cache; /* signal */ struct {