fix: symbol name for native boxed declarations in the interpreter (#12095)
This PR fixes the procedure for finding the mangled symbol name of boxed variants of native functions. Previously, the wrong symbol name has been used for names ending in `_`: For example `test_` mangles to `l_test__` but `test_._boxed` mangles to `l_test___00__boxed`, not `l_test_____boxed` which the compiler would previously wrongly use. This probably didn't affect anybody though since the failure condition is pretty rare: the name of a native function that the interpreter tries to execute would've had to end in `_`.
This commit is contained in:
parent
16873fb123
commit
6bec8adf16
4 changed files with 30 additions and 11 deletions
|
|
@ -56,9 +56,9 @@ public def Environment.getModulePackageByIdx? (env : Environment) (idx : ModuleI
|
|||
Returns the standard base of the native symbol for the compiled constant {lean}`declName`.
|
||||
|
||||
For many constants, this is the full symbol. However, initializers have an additional prefix
|
||||
(i.e., {lit}`_init_`) and boxed functions have an additional suffix (i.e., {lit}`___boxed`).
|
||||
Furthermore, some constants do not use this stem at all (e.g., {lit}`main` and definitions
|
||||
with {lit}`@[export]`).
|
||||
(i.e., {lit}`_init_`) and boxed functions have an additional suffix
|
||||
(see {name}`mkMangledBoxedName`). Furthermore, some constants do not use this stem at all
|
||||
(e.g., {lit}`main` and definitions with {lit}`@[export]`).
|
||||
-/
|
||||
@[export lean_get_symbol_stem]
|
||||
public def getSymbolStem (env : Environment) (declName : Name) : String :=
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Setup
|
||||
import Init.Data.String.Termination
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
namespace String
|
||||
|
||||
|
|
@ -133,6 +133,18 @@ def Name.mangleAux : Name → String
|
|||
public def Name.mangle (n : Name) (pre : String := "l_") : String :=
|
||||
pre ++ Name.mangleAux n
|
||||
|
||||
/--
|
||||
Given `s = nm.mangle pre` for some `nm : Name` and `pre : String` with `nm != Name.anonymous`,
|
||||
returns `(mkBoxedName nm).mangle pre`. This is used in the interpreter to find names of boxed
|
||||
IR declarations.
|
||||
-/
|
||||
@[export lean_mk_mangled_boxed_name]
|
||||
public def mkMangledBoxedName (s : String) : String :=
|
||||
if s.endsWith "__" then
|
||||
s ++ "_00__boxed"
|
||||
else
|
||||
s ++ "___boxed"
|
||||
|
||||
/--
|
||||
The mangled name of the name used to create the module initialization function.
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,6 @@ option_ref<decl> find_ir_decl_boxed(elab_environment const & env, name const & n
|
|||
extern "C" double lean_float_of_nat(lean_obj_arg a);
|
||||
extern "C" float lean_float32_of_nat(lean_obj_arg a);
|
||||
|
||||
static string_ref * g_boxed_mangled_suffix = nullptr;
|
||||
static name * g_interpreter_prefer_native = nullptr;
|
||||
DEBUG_CODE(static name * g_interpreter_step = nullptr;)
|
||||
DEBUG_CODE(static name * g_interpreter_call = nullptr;)
|
||||
|
|
@ -216,6 +215,12 @@ string_ref get_symbol_stem(elab_environment const & env, name const & fn) {
|
|||
return string_ref(lean_get_symbol_stem(env.to_obj_arg(), fn.to_obj_arg()));
|
||||
}
|
||||
|
||||
extern "C" obj_res lean_mk_mangled_boxed_name(obj_arg str);
|
||||
|
||||
string_ref mk_mangled_boxed_name(string_ref const & str) {
|
||||
return string_ref(lean_mk_mangled_boxed_name(str.to_obj_arg()));
|
||||
}
|
||||
|
||||
extern "C" object * lean_ir_format_fn_body_head(object * b);
|
||||
std::string format_fn_body_head(fn_body const & b) {
|
||||
object_ref s(lean_ir_format_fn_body_head(b.to_obj_arg()));
|
||||
|
|
@ -843,7 +848,7 @@ private:
|
|||
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)) {
|
||||
string_ref mangled = get_symbol_stem(m_env, fn);
|
||||
string_ref boxed_mangled(string_append(mangled.to_obj_arg(), g_boxed_mangled_suffix->raw()));
|
||||
string_ref boxed_mangled = mk_mangled_boxed_name(mangled);
|
||||
// check for boxed version first
|
||||
if (void *p_boxed = lookup_symbol_in_cur_exe(boxed_mangled.data())) {
|
||||
e_new.m_native.m_addr = p_boxed;
|
||||
|
|
@ -965,7 +970,7 @@ private:
|
|||
} else {
|
||||
if (decl_tag(e.m_decl) == decl_kind::Extern) {
|
||||
string_ref mangled = get_symbol_stem(m_env, fn);
|
||||
string_ref boxed_mangled(string_append(mangled.to_obj_arg(), g_boxed_mangled_suffix->raw()));
|
||||
string_ref boxed_mangled = mk_mangled_boxed_name(mangled);
|
||||
throw exception(sstream() << "Could not find native implementation of external declaration '" << fn
|
||||
<< "' (symbols '" << boxed_mangled.data() << "' or '" << mangled.data() << "').\n"
|
||||
<< "For declarations from `Init`, `Std`, or `Lean`, you need to set `supportInterpreter := true` "
|
||||
|
|
@ -1212,8 +1217,6 @@ extern "C" LEAN_EXPORT object * lean_run_init(object * env, object * opts, objec
|
|||
}
|
||||
|
||||
void initialize_ir_interpreter() {
|
||||
ir::g_boxed_mangled_suffix = new string_ref("___boxed");
|
||||
mark_persistent(ir::g_boxed_mangled_suffix->raw());
|
||||
ir::g_interpreter_prefer_native = new name({"interpreter", "prefer_native"});
|
||||
ir::g_init_globals = new name_hash_map<object *>();
|
||||
register_bool_option(*ir::g_interpreter_prefer_native, LEAN_DEFAULT_INTERPRETER_PREFER_NATIVE, "(interpreter) whether to use precompiled code where available");
|
||||
|
|
@ -1236,6 +1239,5 @@ void finalize_ir_interpreter() {
|
|||
});
|
||||
delete ir::g_init_globals;
|
||||
delete ir::g_interpreter_prefer_native;
|
||||
delete ir::g_boxed_mangled_suffix;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
module
|
||||
import Lean.Compiler.IR.CompilerM
|
||||
import Lean.Compiler.NameMangling
|
||||
|
||||
/-!
|
||||
# Test behavior of name mangling
|
||||
-/
|
||||
|
||||
def checkMangle (n : Lean.Name) (s : String) : IO Unit := do
|
||||
open Lean IR ExplicitBoxing
|
||||
def checkMangle (n : Name) (s : String) : IO Unit := do
|
||||
if n.mangle "" ≠ s then
|
||||
throw <| .userError s!"failed: {n} mangles to {n.mangle ""} but expected {s}"
|
||||
if .demangle s ≠ n then
|
||||
throw <| .userError s!"failed: {s} demangles to {Lean.Name.demangle s} but expected {n}"
|
||||
if n ≠ .anonymous ∧ mkMangledBoxedName s ≠ (mkBoxedName n).mangle "" then
|
||||
throw <| .userError s!"failed: {mkBoxedName n} mangles to {(mkBoxedName n).mangle ""} but \
|
||||
mkMangledBoxedName produced {mkMangledBoxedName s}"
|
||||
|
||||
/-!
|
||||
Mangling simple identifiers with optional number components and preceding underscores.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue