feat(library/module): reuse pre-imported init module
This commit is contained in:
parent
a26e2c9108
commit
a2bc967fac
5 changed files with 105 additions and 14 deletions
|
|
@ -443,24 +443,41 @@ std::pair<std::vector<module_name>, std::vector<char>> parse_olean(std::istream
|
|||
static void import_module(environment & env, std::string const & module_file_name, module_name const & ref,
|
||||
module_loader const & mod_ldr) {
|
||||
auto res = mod_ldr(module_file_name, ref);
|
||||
if (get_extension(env).m_imported.contains(res.m_module_name)) return;
|
||||
for (auto & dep : res.m_imports) {
|
||||
import_module(env, res.m_module_name, dep, mod_ldr);
|
||||
|
||||
auto & ext0 = get_extension(env);
|
||||
if (ext0.m_imported.contains(res->m_module_name)) return;
|
||||
|
||||
if (ext0.m_imported.empty() && res->m_env) {
|
||||
env = *res->m_env;
|
||||
} else {
|
||||
for (auto & dep : res->m_imports) {
|
||||
import_module(env, res->m_module_name, dep, mod_ldr);
|
||||
}
|
||||
import_module(res->m_modifications, res->m_module_name, env);
|
||||
}
|
||||
|
||||
auto ext = get_extension(env);
|
||||
ext.m_imported.insert(res.m_module_name);
|
||||
ext.m_imported.insert(res->m_module_name);
|
||||
env = update(env, ext);
|
||||
import_module(res.m_modifications, res.m_module_name, env);
|
||||
}
|
||||
|
||||
environment import_module(environment const & env0, std::string const & module_file_name,
|
||||
module_name const & ref,
|
||||
module_loader const & mod_ldr) {
|
||||
environment env = env0;
|
||||
import_module(env, module_file_name, ref, mod_ldr);
|
||||
module_ext ext = get_extension(env);
|
||||
ext.m_direct_imports = cons(ref, ext.m_direct_imports);
|
||||
env = update(env, ext);
|
||||
import_module(env, module_file_name, ref, mod_ldr);
|
||||
return env;
|
||||
}
|
||||
|
||||
environment mk_preimported_module(environment const & initial_env, loaded_module const & lm, module_loader const & mod_ldr) {
|
||||
auto env = initial_env;
|
||||
for (auto & dep : lm.m_imports) {
|
||||
import_module(env, lm.m_module_name, dep, mod_ldr);
|
||||
}
|
||||
import_module(lm.m_modifications, lm.m_module_name, env);
|
||||
return env;
|
||||
}
|
||||
|
||||
|
|
@ -509,12 +526,12 @@ module_loader mk_olean_loader() {
|
|||
std::ifstream in(fn, std::ios_base::binary);
|
||||
auto parsed = parse_olean(in, fn, check_hash);
|
||||
auto modifs = parse_olean_modifications(parsed.second, fn);
|
||||
return loaded_module { fn, parsed.first, modifs };
|
||||
return std::make_shared<loaded_module>(loaded_module { fn, parsed.first, modifs, {} });
|
||||
};
|
||||
}
|
||||
|
||||
module_loader mk_dummy_loader() {
|
||||
return[=] (std::string const &, module_name const &) -> loaded_module {
|
||||
return[=] (std::string const &, module_name const &) -> std::shared_ptr<loaded_module const> {
|
||||
throw exception("module importing disabled");
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Author: Leonardo de Moura
|
|||
#include "kernel/inductive/inductive.h"
|
||||
#include "library/io_state.h"
|
||||
#include "util/task_queue.h"
|
||||
#include "util/lazy_value.h"
|
||||
|
||||
namespace lean {
|
||||
class corrupted_file_exception : public exception {
|
||||
|
|
@ -34,8 +35,10 @@ struct loaded_module {
|
|||
std::string m_module_name;
|
||||
std::vector<module_name> m_imports;
|
||||
modification_list m_modifications;
|
||||
|
||||
lazy_value<environment> m_env;
|
||||
};
|
||||
using module_loader = std::function<loaded_module(std::string const &, module_name const &)>;
|
||||
using module_loader = std::function<std::shared_ptr<loaded_module const> (std::string const &, module_name const &)>;
|
||||
module_loader mk_olean_loader();
|
||||
module_loader mk_dummy_loader();
|
||||
|
||||
|
|
@ -58,6 +61,10 @@ import_module(environment const & env,
|
|||
std::string const & current_mod, module_name const & ref,
|
||||
module_loader const & mod_ldr);
|
||||
|
||||
environment mk_preimported_module(environment const & initial_env,
|
||||
loaded_module const & lm,
|
||||
module_loader const & mod_ldr);
|
||||
|
||||
/** \brief Return the .olean file where decl_name was defined. The result is none if the declaration
|
||||
was not defined in an imported file. */
|
||||
optional<std::string> get_decl_olean(environment const & env, name const & decl_name);
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ public:
|
|||
}
|
||||
|
||||
module_info::parse_result execute() override {
|
||||
auto deps = std::move(m_deps);
|
||||
module_loader import_fn = [=] (module_id const & base, module_name const & import) {
|
||||
for (auto & d : m_deps) {
|
||||
for (auto & d : deps) {
|
||||
if (std::get<0>(d) == base &&
|
||||
std::get<1>(d).m_name == import.m_name &&
|
||||
std::get<1>(d).m_relative == import.m_relative) {
|
||||
|
|
@ -83,7 +84,13 @@ public:
|
|||
|
||||
mod.m_snapshots = std::move(m_snapshots);
|
||||
|
||||
mod.m_loaded_module = export_module(p.env(), get_module_id());
|
||||
auto lm = std::make_shared<loaded_module>(export_module(p.env(), get_module_id()));
|
||||
std::weak_ptr<loaded_module> weak_lm = lm;
|
||||
auto initial_env = m_initial_env;
|
||||
lm->m_env = lazy_value<environment>([initial_env, weak_lm, import_fn] {
|
||||
return mk_preimported_module(initial_env, *weak_lm.lock(), import_fn);
|
||||
});
|
||||
mod.m_loaded_module = lm;
|
||||
|
||||
mod.m_env = optional<environment>(p.env());
|
||||
|
||||
|
|
@ -128,7 +135,7 @@ public:
|
|||
auto olean_fn = olean_of_lean(m_mod->m_mod);
|
||||
exclusive_file_lock output_lock(olean_fn);
|
||||
std::ofstream out(olean_fn, std::ios_base::binary);
|
||||
write_module(res.m_loaded_module, out);
|
||||
write_module(*res.m_loaded_module, out);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
|
@ -193,7 +200,9 @@ void module_mgr::build_module(module_id const & id, bool can_use_olean, name_set
|
|||
return build_module(id, false, orig_module_stack);
|
||||
|
||||
module_info::parse_result res;
|
||||
res.m_loaded_module = { id, parsed_olean.first, parse_olean_modifications(parsed_olean.second, id) };
|
||||
// TODO(gabriel)
|
||||
res.m_loaded_module = std::make_shared<loaded_module>(
|
||||
loaded_module { id, parsed_olean.first, parse_olean_modifications(parsed_olean.second, id), {} });
|
||||
res.m_ok = true;
|
||||
mod->m_result = mk_pure_task_result(res, "Loading " + olean_fn);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ struct module_info {
|
|||
options m_opts;
|
||||
bool m_ok = false;
|
||||
|
||||
loaded_module m_loaded_module;
|
||||
std::shared_ptr<loaded_module const> m_loaded_module;
|
||||
|
||||
snapshot_vector m_snapshots;
|
||||
};
|
||||
|
|
|
|||
58
src/util/lazy_value.h
Normal file
58
src/util/lazy_value.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Gabriel Ebner
|
||||
*/
|
||||
#pragma once
|
||||
#include "util/thread.h"
|
||||
#include <functional>
|
||||
|
||||
namespace lean {
|
||||
|
||||
template <class T>
|
||||
class lazy_value {
|
||||
bool m_nonempty = false;
|
||||
mutex m_mutex;
|
||||
optional<T> m_value;
|
||||
std::exception_ptr m_ex;
|
||||
std::function<T()> m_closure;
|
||||
|
||||
T const & get() {
|
||||
lean_assert(m_nonempty);
|
||||
unique_lock<mutex> _(m_mutex);
|
||||
if (m_value) return *m_value;
|
||||
if (m_ex) std::rethrow_exception(m_ex);
|
||||
try {
|
||||
m_value = { m_closure() };
|
||||
m_closure = {};
|
||||
return *m_value;
|
||||
} catch (...) {
|
||||
m_ex = std::current_exception();
|
||||
m_closure = {};
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
lazy_value() {}
|
||||
lazy_value(std::function<T()> && closure) : m_nonempty(true), m_closure(closure) {}
|
||||
lazy_value(lazy_value const & other) { *this = other; }
|
||||
|
||||
lazy_value & operator=(lazy_value const & other) {
|
||||
unique_lock<mutex> _(const_cast<lazy_value &>(other).m_mutex);
|
||||
m_nonempty = other.m_nonempty;
|
||||
m_value = other.m_value;
|
||||
m_ex = other.m_ex;
|
||||
m_closure = other.m_closure;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return m_nonempty; }
|
||||
|
||||
T const & operator*() const {
|
||||
return const_cast<lazy_value *>(this)->get();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue