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 {
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: