diff --git a/src/library/compiler/ir_interpreter.cpp b/src/library/compiler/ir_interpreter.cpp
index a6fec2437d..d9a257249a 100644
--- a/src/library/compiler/ir_interpreter.cpp
+++ b/src/library/compiler/ir_interpreter.cpp
@@ -298,7 +298,7 @@ void * lookup_symbol_in_cur_exe(char const * sym) {
}
class interpreter;
-LEAN_THREAD_PTR(interpreter, g_interpreter);
+static interpreter & get_interpreter();
class interpreter {
// stack of IR variable slots
@@ -314,12 +314,10 @@ class interpreter {
frame(name const & mFn, size_t mArgBp, size_t mJpBp) : m_fn(mFn), m_arg_bp(mArgBp), m_jp_bp(mJpBp) {}
};
std::vector m_call_stack;
- environment const & m_env;
- options const & m_opts;
+ environment const * m_env;
+ options const * m_opts;
// if `false`, use IR code where possible
bool m_prefer_native;
- // if we were called within the execution of a different interpreter, restore the value of `g_interpreter` in the end
- interpreter * m_prev_interpreter;
struct constant_cache_entry {
bool m_is_scalar;
value m_val;
@@ -352,6 +350,29 @@ class interpreter {
return m_arg_stack[i];
}
+public:
+ template
+ static inline T with_interpreter(environment const & env, options const & opts, std::function const & f) {
+ interpreter & interp = get_interpreter();
+ if (interp.m_env && is_eqp(*interp.m_env, env) && interp.m_opts && is_eqp(*interp.m_opts, opts)) {
+ return f(interp);
+ } else {
+ // We changed threads or the closure was stored and called in a different context.
+ time_task t("interpretation",
+ message_builder(env, get_global_ios(), "foo", pos_info(), message_severity::INFORMATION));
+ abstract_type_context trace_ctx(opts);
+ scope_trace_env scope_trace(env, opts, trace_ctx);
+ flet fl1(interp.m_env, &env);
+ flet fl2(interp.m_opts, &opts);
+ flet fl3(interp.m_prefer_native, opts.get_bool(*g_interpreter_prefer_native, LEAN_DEFAULT_INTERPRETER_PREFER_NATIVE));
+ // both these caches contain data from the Environment, so we cannot reuse them when changing it
+ flet> fl4(interp.m_constant_cache, {});
+ flet> fl5(interp.m_symbol_cache, {});
+ return f(interp);
+ }
+ }
+
+private:
value eval_arg(arg const & a) {
// an "irrelevant" argument is type- or proof-erased; we can use an arbitrary value for it
return arg_is_irrelevant(a) ? box(0) : var(arg_var_id(a));
@@ -383,8 +404,8 @@ class interpreter {
object * mk_stub_closure(decl const & d, unsigned n, object ** args) {
unsigned cls_size = 3 + decl_params(d).size();
object * cls = alloc_closure(get_stub(cls_size), cls_size, 3 + n);
- closure_set(cls, 0, m_env.to_obj_arg());
- closure_set(cls, 1, m_opts.to_obj_arg());
+ closure_set(cls, 0, m_env->to_obj_arg());
+ closure_set(cls, 1, m_opts->to_obj_arg());
closure_set(cls, 2, d.to_obj_arg());
for (unsigned i = 0; i < n ; i++)
closure_set(cls, 3 + i, args[i]);
@@ -712,7 +733,7 @@ class interpreter {
return *e;
} else {
symbol_cache_entry e_new { get_decl(fn), nullptr, false };
- if (m_prefer_native || decl_tag(e_new.m_decl) == decl_kind::Extern || has_init_attribute(m_env, fn)) {
+ if (m_prefer_native || decl_tag(e_new.m_decl) == decl_kind::Extern || has_init_attribute(*m_env, fn)) {
string_ref mangled = name_mangle(fn, *g_mangle_prefix);
string_ref boxed_mangled(string_append(mangled.to_obj_arg(), g_boxed_mangled_suffix->raw()));
// check for boxed version first
@@ -731,7 +752,7 @@ class interpreter {
/** \brief Retrieve Lean declaration from environment. */
decl get_decl(name const & fn) {
- option_ref d = find_ir_decl(m_env, fn);
+ option_ref d = find_ir_decl(*m_env, fn);
if (!d) {
throw exception(sstream() << "unknown declaration '" << fn << "'");
}
@@ -751,7 +772,7 @@ class interpreter {
return *o;
}
- if (get_regular_init_fn_name_for(m_env, fn)) {
+ if (get_regular_init_fn_name_for(*m_env, fn)) {
// We don't know whether `[init]` decls can be re-executed, so let's not.
throw exception(sstream() << "cannot evaluate `[init]` declaration '" << fn << "' in the same module");
}
@@ -838,21 +859,13 @@ class interpreter {
return r;
}
- // closure stub stub
+ // static closure stub
static object * stub_m_aux(object ** args) {
environment env(args[0]);
options opts(args[1]);
- if (g_interpreter && is_eqp(g_interpreter->m_env, env) && is_eqp(g_interpreter->m_opts, opts)) {
- return g_interpreter->stub_m(args);
- } else {
- // We changed threads or the closure was stored and called in a different context.
- // Create new interpreter with new stacks.
- time_task t("interpretation",
- message_builder(env, get_global_ios(), "foo", pos_info(), message_severity::INFORMATION));
- abstract_type_context trace_ctx(opts);
- scope_trace_env scope_trace(env, opts, trace_ctx);
- return interpreter(env, opts).stub_m(args);
- }
+ return with_interpreter