1
Fork 0

Improve name mangling for gdb

Remove __extensions__ from method symbols as well as the meth_XXX. The XXX is
now used to append a few characters at the end of the name of the symbol.

Closes #6602
This commit is contained in:
Alex Crichton 2013-09-02 22:34:37 -07:00
parent 36a4af49e0
commit 7baff57f26
5 changed files with 100 additions and 59 deletions

View file

@ -663,8 +663,7 @@ pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
pub fn symbol_hash(tcx: ty::ctxt, pub fn symbol_hash(tcx: ty::ctxt,
symbol_hasher: &mut hash::State, symbol_hasher: &mut hash::State,
t: ty::t, t: ty::t,
link_meta: LinkMeta) link_meta: LinkMeta) -> @str {
-> @str {
// NB: do *not* use abbrevs here as we want the symbol names // NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate. // to be independent of one another in the crate.
@ -719,7 +718,7 @@ pub fn sanitize(s: &str) -> ~str {
'a' .. 'z' 'a' .. 'z'
| 'A' .. 'Z' | 'A' .. 'Z'
| '0' .. '9' | '0' .. '9'
| '_' => result.push_char(c), | '_' | '.' => result.push_char(c),
_ => { _ => {
let mut tstr = ~""; let mut tstr = ~"";
@ -740,22 +739,37 @@ pub fn sanitize(s: &str) -> ~str {
return result; return result;
} }
pub fn mangle(sess: Session, ss: path) -> ~str { pub fn mangle(sess: Session, ss: path,
hash: Option<&str>, vers: Option<&str>) -> ~str {
// Follow C++ namespace-mangling style, see // Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info. // http://en.wikipedia.org/wiki/Name_mangling for more info.
//
// It turns out that on OSX you can actually have arbitrary symbols in
// function names (at least when given to LLVM), but this is not possible
// when using unix's linker. Perhaps one day when we just a linker from LLVM
// we won't need to do this name mangling. The problem with name mangling is
// that it seriously limits the available characters. For example we can't
// have things like @T or ~[T] in symbol names when one would theoretically
// want them for things like impls of traits on that type.
//
// To be able to work on all platforms and get *some* reasonable output, we
// use C++ name-mangling.
let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
let push = |s: &str| {
let sani = sanitize(s);
n.push_str(fmt!("%u%s", sani.len(), sani));
};
// First, connect each component with <len, name> pairs. // First, connect each component with <len, name> pairs.
for s in ss.iter() { for s in ss.iter() {
match *s { match *s {
path_name(s) | path_mod(s) | path_pretty_name(s, _) => { path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
let sani = sanitize(sess.str_of(s)); push(sess.str_of(s))
n.push_str(fmt!("%u%s", sani.len(), sani));
} }
} }
} }
n.push_char('E'); // End name-sequence.
// next, if any identifiers are "pretty" and need extra information tacked // next, if any identifiers are "pretty" and need extra information tacked
// on, then use the hash to generate two unique characters. For now // on, then use the hash to generate two unique characters. For now
@ -764,17 +778,27 @@ pub fn mangle(sess: Session, ss: path) -> ~str {
"abcdefghijklmnopqrstuvwxyz\ "abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\
0123456789"; 0123456789";
let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" };
for s in ss.iter() { for s in ss.iter() {
match *s { match *s {
path_pretty_name(_, extra) => { path_pretty_name(_, extra) => {
let hi = (extra >> 32) as u32 as uint; let hi = (extra >> 32) as u32 as uint;
let lo = extra as u32 as uint; let lo = extra as u32 as uint;
n.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char); hash.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char);
n.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char); hash.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char);
} }
_ => {} _ => {}
} }
} }
if hash.len() > 0 {
push(hash);
}
match vers {
Some(s) => push(s),
None => {}
}
n.push_char('E'); // End name-sequence.
n n
} }
@ -782,10 +806,15 @@ pub fn exported_name(sess: Session,
path: path, path: path,
hash: &str, hash: &str,
vers: &str) -> ~str { vers: &str) -> ~str {
mangle(sess, // The version will get mangled to have a leading '_', but it makes more
vec::append_one( // sense to lead with a 'v' b/c this is a version...
vec::append_one(path, path_name(sess.ident_of(hash))), let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) {
path_name(sess.ident_of(vers)))) "v" + vers
} else {
vers.to_owned()
};
mangle(sess, path, Some(hash), Some(vers.as_slice()))
} }
pub fn mangle_exported_name(ccx: &mut CrateContext, pub fn mangle_exported_name(ccx: &mut CrateContext,
@ -803,31 +832,33 @@ pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext,
let s = ppaux::ty_to_short_str(ccx.tcx, t); let s = ppaux::ty_to_short_str(ccx.tcx, t);
let hash = get_symbol_hash(ccx, t); let hash = get_symbol_hash(ccx, t);
return mangle(ccx.sess, return mangle(ccx.sess,
~[path_name(ccx.sess.ident_of(name)), ~[path_name(ccx.sess.ident_of(name)),
path_name(ccx.sess.ident_of(s)), path_name(ccx.sess.ident_of(s))],
path_name(ccx.sess.ident_of(hash))]); Some(hash.as_slice()),
None);
} }
pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext, pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext,
t: ty::t, t: ty::t,
name: &str) -> ~str { name: &str) -> ~str {
let s = ppaux::ty_to_str(ccx.tcx, t); let s = ppaux::ty_to_str(ccx.tcx, t);
let hash = get_symbol_hash(ccx, t); let hash = get_symbol_hash(ccx, t);
return mangle(ccx.sess, return mangle(ccx.sess,
~[path_name(ccx.sess.ident_of(s)), ~[path_name(ccx.sess.ident_of(s)),
path_name(ccx.sess.ident_of(hash)), path_name(gensym_name(name))],
path_name(gensym_name(name))]); Some(hash.as_slice()),
None);
} }
pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext, pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext,
mut path: path, mut path: path,
flav: &str) -> ~str { flav: &str) -> ~str {
path.push(path_name(gensym_name(flav))); path.push(path_name(gensym_name(flav)));
mangle(ccx.sess, path) mangle(ccx.sess, path, None, None)
} }
pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str { pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str {
mangle(ccx.sess, path) mangle(ccx.sess, path, None, None)
} }
pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str { pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str {

View file

@ -77,7 +77,7 @@ use std::local_data;
use extra::time; use extra::time;
use extra::sort; use extra::sort;
use syntax::ast::Ident; use syntax::ast::Ident;
use syntax::ast_map::{path, path_elt_to_str, path_name}; use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name};
use syntax::ast_util::{local_def}; use syntax::ast_util::{local_def};
use syntax::attr; use syntax::attr;
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
@ -2646,8 +2646,7 @@ pub fn register_method(ccx: @mut CrateContext,
let mty = ty::node_id_to_type(ccx.tcx, id); let mty = ty::node_id_to_type(ccx.tcx, id);
let mut path = (*path).clone(); let mut path = (*path).clone();
path.push(path_name(gensym_name("meth"))); path.push(path_pretty_name(m.ident, token::gensym("meth") as u64));
path.push(path_name(m.ident));
let sym = exported_name(ccx, path, mty, m.attrs); let sym = exported_name(ccx, path, mty, m.attrs);

View file

@ -16,20 +16,20 @@ use ast_util;
use codemap::Span; use codemap::Span;
use codemap; use codemap;
use diagnostic::span_handler; use diagnostic::span_handler;
use parse::token::get_ident_interner;
use parse::token::ident_interner; use parse::token::ident_interner;
use parse::token::special_idents; use parse::token::special_idents;
use print::pprust; use print::pprust;
use visit::{Visitor, fn_kind}; use visit::{Visitor, fn_kind};
use visit; use visit;
use std::hash;
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::vec; use std::vec;
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
pub enum path_elt { pub enum path_elt {
path_mod(Ident), path_mod(Ident),
path_name(Ident) path_name(Ident),
// A pretty name can come from an `impl` block. We attempt to select a // A pretty name can come from an `impl` block. We attempt to select a
// reasonable name for debuggers to see, but to guarantee uniqueness with // reasonable name for debuggers to see, but to guarantee uniqueness with
@ -98,8 +98,8 @@ pub struct Ctx {
} }
impl Ctx { impl Ctx {
fn extend(&self, elt: Ident) -> @path { fn extend(&self, elt: path_elt) -> @path {
@vec::append(self.path.clone(), [path_name(elt)]) @vec::append(self.path.clone(), [elt])
} }
fn map_method(&mut self, fn map_method(&mut self,
@ -120,7 +120,7 @@ impl Ctx {
struct_def: @ast::struct_def, struct_def: @ast::struct_def,
parent_node: ast_node, parent_node: ast_node,
ident: ast::Ident) { ident: ast::Ident) {
let p = self.extend(ident); let p = self.extend(path_name(ident));
// If this is a tuple-like struct, register the constructor. // If this is a tuple-like struct, register the constructor.
match struct_def.ctor_id { match struct_def.ctor_id {
@ -196,6 +196,28 @@ impl Ctx {
visit::walk_pat(self, pat, ()); visit::walk_pat(self, pat, ());
} }
fn impl_pretty_name(&self, trait_ref: &Option<trait_ref>,
ty: &Ty, default: Ident) -> path_elt {
let itr = get_ident_interner();
let ty_ident = match ty.node {
ty_path(ref path, _, _) => path.segments.last().identifier,
_ => default
};
let hash = (trait_ref, ty).hash();
match *trait_ref {
None => path_pretty_name(ty_ident, hash),
Some(ref trait_ref) => {
// XXX: this dollar sign is actually a relic of being one of the
// very few valid symbol names on unix. These kinds of
// details shouldn't be exposed way up here in the ast.
let s = fmt!("%s$%s",
itr.get(trait_ref.path.segments.last().identifier.name),
itr.get(ty_ident.name));
path_pretty_name(Ident::new(itr.gensym(s)), hash)
}
}
}
} }
impl Visitor<()> for Ctx { impl Visitor<()> for Ctx {
@ -205,40 +227,27 @@ impl Visitor<()> for Ctx {
self.map.insert(i.id, node_item(i, item_path)); self.map.insert(i.id, node_item(i, item_path));
match i.node { match i.node {
item_impl(_, ref maybe_trait, ref ty, ref ms) => { item_impl(_, ref maybe_trait, ref ty, ref ms) => {
let impl_did = ast_util::local_def(i.id);
for m in ms.iter() {
let extended = { self.extend(i.ident) };
self.map_method(impl_did, extended, *m, false)
}
// Right now the ident on impls is __extensions__ which isn't // Right now the ident on impls is __extensions__ which isn't
// very pretty when debugging, so attempt to select a better // very pretty when debugging, so attempt to select a better
// name to use. // name to use.
let name = match *maybe_trait { let elt = self.impl_pretty_name(maybe_trait, ty, i.ident);
Some(ref trait_ref) => {
trait_ref.path.segments.last().identifier
}
None => {
match ty.node {
ty_path(ref p, _, _) => {
p.segments.last().identifier
}
// oh well, just give up for now
_ => { i.ident }
}
}
};
let hash = hash::hash_keyed_2(maybe_trait, ty, 0, 0); let impl_did = ast_util::local_def(i.id);
self.path.push(path_pretty_name(name, hash)); for m in ms.iter() {
let extended = { self.extend(elt) };
self.map_method(impl_did, extended, *m, false)
}
self.path.push(elt);
} }
item_enum(ref enum_definition, _) => { item_enum(ref enum_definition, _) => {
for v in (*enum_definition).variants.iter() { for v in (*enum_definition).variants.iter() {
let elt = path_name(i.ident);
// FIXME #2543: bad clone // FIXME #2543: bad clone
self.map.insert(v.node.id, self.map.insert(v.node.id,
node_variant((*v).clone(), node_variant((*v).clone(),
i, i,
self.extend(i.ident))); self.extend(elt)));
} }
} }
item_foreign_mod(ref nm) => { item_foreign_mod(ref nm) => {
@ -257,7 +266,9 @@ impl Visitor<()> for Ctx {
// FIXME (#2543) // FIXME (#2543)
if nm.sort == if nm.sort ==
ast::named { ast::named {
self.extend(i.ident) let e = path_name(
i.ident);
self.extend(e)
} else { } else {
// Anonymous extern // Anonymous extern
// mods go in the // mods go in the
@ -276,7 +287,7 @@ impl Visitor<()> for Ctx {
self.map.insert(p.ref_id, node_item(i, item_path)); self.map.insert(p.ref_id, node_item(i, item_path));
} }
for tm in methods.iter() { for tm in methods.iter() {
let ext = { self.extend(i.ident) }; let ext = { self.extend(path_name(i.ident)) };
let d_id = ast_util::local_def(i.id); let d_id = ast_util::local_def(i.id);
match *tm { match *tm {
required(ref m) => { required(ref m) => {

View file

@ -15,6 +15,6 @@ use ambig_impl_2_lib::me;
trait me { trait me {
fn me(&self) -> uint; fn me(&self) -> uint;
} }
impl me for uint { fn me(&self) -> uint { *self } } //~ NOTE is `__extensions__::me` impl me for uint { fn me(&self) -> uint { *self } } //~ NOTE is `me$uint::me`
fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope
//~^ NOTE is `ambig_impl_2_lib::__extensions__::me` //~^ NOTE is `ambig_impl_2_lib::__extensions__::me`

View file

@ -13,11 +13,11 @@ trait foo {
} }
impl foo for ~[uint] { impl foo for ~[uint] {
fn foo(&self) -> int {1} //~ NOTE candidate #1 is `__extensions__::foo` fn foo(&self) -> int {1} //~ NOTE candidate #1 is `foo$__extensions__::foo`
} }
impl foo for ~[int] { impl foo for ~[int] {
fn foo(&self) -> int {2} //~ NOTE candidate #2 is `__extensions__::foo` fn foo(&self) -> int {2} //~ NOTE candidate #2 is `foo$__extensions__::foo`
} }
fn main() { fn main() {