More work on proper linkage name-mangling. Almost right, aside from version numbers.

This commit is contained in:
Graydon Hoare 2011-06-07 17:54:22 -07:00
parent 7034a28241
commit 721c5bbee8
9 changed files with 381 additions and 143 deletions

View File

@ -1,8 +1,18 @@
import driver::session;
import lib::llvm::llvm;
import middle::trans;
import middle::metadata;
import middle::ty;
import std::str;
import std::fs;
import std::vec;
import std::option;
import option::some;
import option::none;
import std::sha1::sha1;
import std::sort;
import trans::crate_ctxt;
import front::ast;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
@ -49,7 +59,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod);
llvm::LLVMDisposeModule(llintrinsicsmod);
if (linkres == False) {
llvm_err(sess, "couldn't link the module with the intrinsics");
fail;
@ -58,7 +68,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
mod write {
fn is_object_or_assembly_or_exe(output_type ot) -> bool {
if ( (ot == output_type_assembly) ||
if ( (ot == output_type_assembly) ||
(ot == output_type_object) ||
(ot == output_type_exe) ) {
ret true;
@ -218,3 +228,235 @@ mod write {
}
}
/*
* Name mangling and its relationship to metadata. This is complex. Read
* carefully.
*
* The semantic model of Rust linkage is, broadly, that "there's no global
* namespace" between crates. Our aim is to preserve the illusion of this
* model despite the fact that it's not *quite* possible to implement on
* modern linkers. We initially didn't use system linkers at all, but have
* been convinced of their utility.
*
* There are a few issues to handle:
*
* - Linkers operate on a flat namespace, so we have to flatten names.
* We do this using the C++ namespace-mangling technique. Foo::bar
* symbols and such.
*
* - Symbols with the same name but different types need to get different
* linkage-names. We do this by hashing a string-encoding of the type into
* a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
* we use SHA1) to "prevent collisions". This is not airtight but 16 hex
* digits on uniform probability means you're going to need 2**32 same-name
* symbols in the same process before you're even hitting birthday-paradox
* collision probability.
*
* - Symbols in dirrerent crates but with same names "within" the crate need
* to get different linkage-names.
*
* So here is what we do:
*
* - Separate the meta tags into two sets: exported and local. Only work with
* the exported ones when considering linkage.
*
* - Consider two exported tags as special (and madatory): name and vers.
* Every crate gets them; if it doesn't name them explicitly we infer them
* as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
*
* - Define CMETA as all the non-name, non-vers exported meta tags in the
* crate (in sorted order).
*
* - Define CMH as hash(CMETA).
*
* - Compile our crate to lib CNAME-CMH-CVERS.so
*
* - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
*
* - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
* name, non-name metadata, and type sense, and versioned in the way
* system linkers understand.
*
*/
iter crate_export_metas(ast::crate c) -> @ast::meta_item {
for (@ast::crate_directive cdir in c.node.directives) {
alt (cdir.node) {
case (ast::cdir_meta(?v, ?mis)) {
if (v == ast::export_meta) {
for (@ast::meta_item mi in mis) {
put mi;
}
}
}
case (_) {}
}
}
}
fn get_crate_meta(&session::session sess,
&ast::crate c, str k, str default,
bool warn_default) -> str {
let vec[@ast::meta_item] v = [];
for each (@ast::meta_item mi in crate_export_metas(c)) {
if (mi.node.name == k) {
v += [mi];
}
}
alt (vec::len(v)) {
case (0u) {
if (warn_default) {
sess.warn(#fmt("missing meta '%s', using '%s' as default",
k, default));
}
ret default;
}
case (1u) {
ret v.(0).node.value;
}
case (_) {
sess.span_err(v.(1).span, #fmt("duplicate meta '%s'", k));
}
}
}
// This calculates CMH as defined above
fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str {
fn lteq(&@ast::meta_item ma,
&@ast::meta_item mb) -> bool {
ret ma.node.name <= mb.node.name;
}
fn len_and_str(&str s) -> str {
ret #fmt("%u_%s", str::byte_len(s), s);
}
let vec[mutable @ast::meta_item] v = [mutable];
for each (@ast::meta_item mi in crate_export_metas(crate)) {
if (mi.node.name != "name" &&
mi.node.name != "vers") {
v += [mutable mi];
}
}
sort::quick_sort(lteq, v);
sha.reset();
for (@ast::meta_item m in v) {
sha.input_str(len_and_str(m.node.name));
sha.input_str(len_and_str(m.node.value));
}
ret truncated_sha1_result(sha);
}
fn crate_meta_name(&session::session sess, &ast::crate crate,
&str output) -> str {
auto os = str::split(fs::basename(output), '.' as u8);
assert vec::len(os) >= 2u;
vec::pop(os);
ret get_crate_meta(sess, crate, "name", str::connect(os, "."),
sess.get_opts().shared);
}
fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str {
ret get_crate_meta(sess, crate, "vers", "0.0",
sess.get_opts().shared);
}
fn truncated_sha1_result(sha1 sha) -> str {
ret str::substr(sha.result_str(), 0u, 16u);
}
// This calculates STH for a symbol, as defined above
fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t,
str crate_meta_name,
str crate_meta_extras_hash) -> str {
// NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate.
auto cx = @rec(ds=metadata::def_to_str, tcx=tcx,
abbrevs=metadata::ac_no_abbrevs);
sha.reset();
sha.input_str(crate_meta_name);
sha.input_str("-");
sha.input_str(crate_meta_name);
sha.input_str("-");
sha.input_str(metadata::Encode::ty_str(cx, t));
auto hash = truncated_sha1_result(sha);
// Prefix with _ so that it never blends into adjacent digits
ret "_" + hash;
}
fn get_symbol_hash(&@crate_ctxt ccx, &ty::t t) -> str {
auto hash = "";
alt (ccx.type_sha1s.find(t)) {
case (some(?h)) { hash = h; }
case (none) {
hash = symbol_hash(ccx.tcx, ccx.sha, t,
ccx.crate_meta_name,
ccx.crate_meta_extras_hash);
ccx.type_sha1s.insert(t, hash);
}
}
ret hash;
}
fn mangle(&vec[str] ss) -> str {
// Follow C++ namespace-mangling style
auto n = "_ZN"; // Begin name-sequence.
for (str s in ss) {
n += #fmt("%u%s", str::byte_len(s), s);
}
n += "E"; // End name-sequence.
ret n;
}
fn exported_name(&vec[str] path, &str hash, &str vers) -> str {
// FIXME: versioning isn't working yet
ret mangle(path + [hash]); // + "@" + vers;
}
fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path,
&ty::t t) -> str {
auto hash = get_symbol_hash(ccx, t);
ret exported_name(path, hash, ccx.crate_meta_vers);
}
fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t,
&str name) -> str {
auto f = metadata::def_to_str;
auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs);
auto s = ty::ty_to_short_str(ccx.tcx, t);
auto hash = get_symbol_hash(ccx, t);
ret mangle([name, s, hash]);
}
fn mangle_internal_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path,
&str flav) -> str {
ret mangle(path + [ccx.names.next(flav)]);
}
fn mangle_internal_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str {
ret mangle(path);
}
fn mangle_internal_name_by_seq(&@crate_ctxt ccx, &str flav) -> str {
ret ccx.names.next(flav);
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//

View File

@ -6,6 +6,9 @@ import std::uint;
import std::term;
import std::io;
import std::map;
import std::option;
import std::option::some;
import std::option::none;
tag os {
os_win32;
@ -48,9 +51,16 @@ fn span_to_str(span sp, codemap::codemap cm) -> str {
lo.col, hi.line, hi.col));
}
fn emit_diagnostic(span sp, str msg, str kind, u8 color,
fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
codemap::codemap cm) {
io::stdout().write_str(span_to_str(sp, cm) + ": ");
auto ss = "<input>:0:0:0:0";
alt (sp) {
case (some(?ssp)) {
ss = span_to_str(ssp, cm);
}
case (none) {}
}
io::stdout().write_str(ss + ": ");
if (term::color_supported()) {
term::fg(io::stdout().get_buf_writer(), color);
@ -85,12 +95,12 @@ state obj session(ast::crate_num cnum,
fn span_err(span sp, str msg) -> ! {
// FIXME: Use constants, but rustboot doesn't know how to export them.
emit_diagnostic(sp, msg, "error", 9u8, cm);
emit_diagnostic(some(sp), msg, "error", 9u8, cm);
fail;
}
fn err(str msg) -> ! {
log_err #fmt("error: %s", msg);
emit_diagnostic(none[span], msg, "error", 9u8, cm);
fail;
}
@ -103,29 +113,32 @@ state obj session(ast::crate_num cnum,
fn span_warn(span sp, str msg) {
// FIXME: Use constants, but rustboot doesn't know how to export them.
emit_diagnostic(sp, msg, "warning", 11u8, cm);
emit_diagnostic(some(sp), msg, "warning", 11u8, cm);
}
fn warn(str msg) {
emit_diagnostic(none[span], msg, "warning", 11u8, cm);
}
fn span_note(span sp, str msg) {
// FIXME: Use constants, but rustboot doesn't know how to export them.
emit_diagnostic(sp, msg, "note", 10u8, cm);
emit_diagnostic(some(sp), msg, "note", 10u8, cm);
}
fn span_bug(span sp, str msg) -> ! {
self.span_err(sp, #fmt("internal compiler error %s", msg));
}
fn bug(str msg) -> ! {
log_err #fmt("error: internal compiler error %s", msg);
fail;
self.err(#fmt("internal compiler error %s", msg));
}
fn span_unimpl(span sp, str msg) -> ! {
// FIXME: Use constants, but rustboot doesn't know how to export them.
emit_diagnostic(sp, "internal compiler error: unimplemented " + msg,
"error", 9u8, cm);
fail;
self.span_bug(sp, "unimplemented " + msg);
}
fn unimpl(str msg) -> ! {
log_err #fmt("error: unimplemented %s", msg);
fail;
self.bug("unimplemented " + msg);
}
fn get_external_crate(int num) -> crate_metadata {

View File

@ -71,6 +71,11 @@ type crate = spanned[crate_];
type crate_ = rec(vec[@crate_directive] directives,
_mod module);
tag meta_visibility {
export_meta;
local_meta;
}
tag crate_directive_ {
cdir_expr(@expr);
// FIXME: cdir_let should be eliminated
@ -80,7 +85,7 @@ tag crate_directive_ {
cdir_src_mod(ident, option::t[filename]);
cdir_dir_mod(ident, option::t[filename], vec[@crate_directive]);
cdir_view_item(@view_item);
cdir_meta(vec[@meta_item]);
cdir_meta(meta_visibility, vec[@meta_item]);
cdir_syntax(path);
cdir_auth(path, _auth);
}

View File

@ -418,8 +418,13 @@ fn eval_crate_directive(ctx cx,
vec::push[@ast::view_item](view_items, vi);
}
case (ast::cdir_meta(?mi)) {
cx.sess.add_metadata(mi);
case (ast::cdir_meta(?vi, ?mi)) {
// FIXME: we should actually record, for documentation-sake,
// the metadata that's not exported. It would be nice to have
// compiled-in to the target crate, not just in theh AST.
if (vi == ast::export_meta) {
cx.sess.add_metadata(mi);
}
}
case (ast::cdir_syntax(?pth)) {}

View File

@ -2362,10 +2362,14 @@ fn parse_crate_directive(&parser p) -> ast::crate_directive
expect(p, token::SEMI);
ret spanned(lo, hi, ast::cdir_auth(n, a));
} else if (eat_word(p, "meta")) {
auto mv = ast::local_meta;
if (eat_word(p, "export")) {
mv = ast::export_meta;
}
auto mis = parse_meta(p);
auto hi = p.get_hi_pos();
expect(p, token::SEMI);
ret spanned(lo, hi, ast::cdir_meta(mis));
ret spanned(lo, hi, ast::cdir_meta(mv, mis));
} else if (eat_word(p, "mod")) {
auto id = parse_ident(p);
auto file_opt = none[filename];

View File

@ -6,7 +6,7 @@
// particular definition to the LLVM IR output we're producing.
//
// Hopefully useful general knowledge about trans:
//
//
// * There's no way to find out the ty::t type of a ValueRef. Doing so
// would be "trying to get the eggs out of an omelette" (credit:
// pcwalton). You can, instead, find out its TypeRef by calling val_ty,
@ -24,6 +24,7 @@ import std::map::hashmap;
import std::option;
import std::option::some;
import std::option::none;
import std::fs;
import front::ast;
import front::creader;
@ -62,6 +63,15 @@ import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::Bool;
import link::mangle_internal_name_by_type_only;
import link::mangle_internal_name_by_seq;
import link::mangle_internal_name_by_path;
import link::mangle_internal_name_by_path_and_seq;
import link::mangle_exported_name;
import link::crate_meta_name;
import link::crate_meta_vers;
import link::crate_meta_extras_hash;
state obj namegen(mutable int i) {
fn next(str prefix) -> str {
i += 1;
@ -119,6 +129,9 @@ state type crate_ctxt = rec(session::session sess,
@ast::native_item] native_items,
hashmap[ast::def_id, str] item_symbols,
mutable option::t[ValueRef] main_fn,
str crate_meta_name,
str crate_meta_vers,
str crate_meta_extras_hash,
// TODO: hashmap[tup(tag_id,subtys), @tag_info]
hashmap[ty::t, uint] tag_sizes,
hashmap[ast::def_id, ValueRef] discrims,
@ -166,14 +179,14 @@ type fn_ctxt = rec(
ValueRef lltaskptr,
ValueRef llenv,
ValueRef llretptr,
// The next three elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in the
// function, due to LLVM's quirks.
// A block for all the function's allocas, so that LLVM will coalesce them
// into a single alloca call.
mutable BasicBlockRef llallocas,
mutable BasicBlockRef llallocas,
// A block containing code that copies incoming arguments to space already
// allocated by code in the llallocas block. (LLVM requires that
@ -313,73 +326,6 @@ fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt {
ret @rec(path = cx.path + [name] with *cx);
}
fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str {
auto hash = "";
alt (ccx.type_sha1s.find(t)) {
case (some(?h)) { hash = h; }
case (none) {
ccx.sha.reset();
auto f = metadata::def_to_str;
// NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate.
auto cx = @rec(ds=f,
tcx=ccx.tcx,
abbrevs=metadata::ac_no_abbrevs);
ccx.sha.input_str(metadata::Encode::ty_str(cx, t));
hash = str::substr(ccx.sha.result_str(), 0u, 16u);
// Prefix with _ so that it never blends into adjacent digits
hash = "_" + hash;
ccx.type_sha1s.insert(t, hash);
}
}
ret hash;
}
fn mangle(&vec[str] ss) -> str {
if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) {
ret "_rust_main";
}
// Follow C++ namespace-mangling style
auto n = "_ZN"; // Begin name-sequence.
for (str s in ss) {
n += #fmt("%u%s", str::byte_len(s), s);
}
n += "E"; // End name-sequence.
ret n;
}
fn mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str {
auto hash = get_type_sha1(ccx, t);
ret mangle(path + [hash]);
}
fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str {
auto f = metadata::def_to_str;
auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs);
auto s = ty::ty_to_short_str(ccx.tcx, t);
auto hash = get_type_sha1(ccx, t);
ret mangle([name, s, hash]);
}
fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path,
&str flav) -> str {
ret mangle(path + [ccx.names.next(flav)]);
}
fn mangle_name_by_path(&vec[str] path) -> str {
ret mangle(path);
}
fn mangle_name_by_seq(&@crate_ctxt ccx, &str flav) -> str {
ret ccx.names.next(flav);
}
fn res(@block_ctxt bcx, ValueRef val) -> result {
ret rec(bcx = bcx,
val = val);
@ -1917,10 +1863,10 @@ fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t,
auto name;
if (cx.ccx.sess.get_opts().debuginfo) {
name = mangle_name_by_type_only(cx.ccx, t, "tydesc");
name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
name = sanitize(name);
} else {
name = mangle_name_by_seq(cx.ccx, "tydesc");
name = mangle_internal_name_by_seq(cx.ccx, "tydesc");
}
auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn),
@ -1951,10 +1897,12 @@ fn declare_generic_glue(&@local_ctxt cx,
&str name) -> ValueRef {
auto fn_nm;
if (cx.ccx.sess.get_opts().debuginfo) {
fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name);
fn_nm = mangle_internal_name_by_type_only(cx.ccx, t,
"glue_" + name);
fn_nm = sanitize(fn_nm);
} else {
fn_nm = mangle_name_by_seq(cx.ccx, "glue_" + name);
fn_nm = mangle_internal_name_by_seq(cx.ccx,
"glue_" + name);
}
auto llfn = decl_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty);
set_glue_inlining(cx, llfn, t);
@ -4106,7 +4054,8 @@ fn trans_for_each(&@block_ctxt cx,
// Step 2: Declare foreach body function.
let str s = mangle_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach");
let str s = mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path,
"foreach");
// The 'env' arg entering the body function is a fake env member (as in
// the env-part of the normal rust calling convention) that actually
@ -4805,7 +4754,8 @@ fn trans_bind_thunk(&@local_ctxt cx,
// Construct a thunk-call with signature incoming_fty, and that copies
// args forward into a call to outgoing_fty:
let str s = mangle_name_by_path_and_seq(cx.ccx, cx.path, "thunk");
let str s = mangle_internal_name_by_path_and_seq(cx.ccx, cx.path,
"thunk");
let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, sp,
incoming_fty));
let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod,
@ -5823,13 +5773,17 @@ fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result {
auto lcx = cx.fcx.lcx;
auto modname = str::connect(lcx.module_path, "::");
auto modname = link::mangle_internal_name_by_path(lcx.ccx,
lcx.module_path);
auto global;
if (lcx.ccx.module_data.contains_key(modname)) {
global = lcx.ccx.module_data.get(modname);
} else {
global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(),
str::buf("_rust_mod_log_" + modname));
auto s =
link::mangle_internal_name_by_path_and_seq(lcx.ccx,
lcx.module_path,
"loglevel");
global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s));
llvm::LLVMSetGlobalConstant(global, False);
llvm::LLVMSetInitializer(global, C_null(T_int()));
llvm::LLVMSetLinkage(global, lib::llvm::LLVMInternalLinkage
@ -6225,8 +6179,8 @@ fn trans_spawn(&@block_ctxt cx,
ret res(bcx, new_task);
}
fn mk_spawn_wrapper(&@block_ctxt cx,
&@ast::expr func,
fn mk_spawn_wrapper(&@block_ctxt cx,
&@ast::expr func,
&ty::t args_ty) -> result {
auto llmod = cx.fcx.lcx.ccx.llmod;
let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty);
@ -6239,9 +6193,9 @@ fn mk_spawn_wrapper(&@block_ctxt cx,
// TODO: construct a name based on tname
let str wrap_name =
mangle_name_by_path_and_seq(cx.fcx.lcx.ccx,
cx.fcx.lcx.path,
"spawn_wrapper");
mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx,
cx.fcx.lcx.path,
"spawn_wrapper");
auto llfndecl = decl_fastcall_fn(llmod, wrap_name,
wrapper_fn_type);
@ -6252,7 +6206,7 @@ fn mk_spawn_wrapper(&@block_ctxt cx,
// 3u to skip the three implicit args
let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
let vec[ValueRef] child_args =
let vec[ValueRef] child_args =
[llvm::LLVMGetParam(fcx.llfn, 0u),
llvm::LLVMGetParam(fcx.llfn, 1u),
llvm::LLVMGetParam(fcx.llfn, 2u)];
@ -6271,19 +6225,19 @@ fn mk_spawn_wrapper(&@block_ctxt cx,
}
}
}
// Find the function
auto fnptr = trans_lval(fbcx, func).res;
fbcx = fnptr.bcx;
auto llfnptr = fbcx.build.GEP(fnptr.val,
[C_int(0), C_int(0)]);
auto llfn = fbcx.build.Load(llfnptr);
fbcx.build.FastCall(llfn,
child_args);
fbcx.build.RetVoid();
finish_fn(fcx, fbcx.llbb);
// TODO: make sure we clean up everything we need to.
@ -6719,7 +6673,7 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
let vec[ast::ty_param] obj_typarams = [];
let vec[ast::obj_field] obj_fields = [];
ret @rec(path=pth,
module_path=[crate_name(ccx, "main")],
module_path=[ccx.crate_meta_name],
obj_typarams = obj_typarams,
obj_fields = obj_fields,
ccx = ccx);
@ -7094,7 +7048,7 @@ fn create_vtbl(@local_ctxt cx,
let @local_ctxt mcx = @rec(path = cx.path + ["method",
m.node.ident] with *cx);
let str s = mangle_name_by_path(mcx.path);
let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path);
let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s,
llfnty);
cx.ccx.item_ids.insert(m.node.id, llfn);
@ -7106,7 +7060,8 @@ fn create_vtbl(@local_ctxt cx,
methods += [llfn];
}
auto vtbl = C_struct(methods);
auto vtbl_name = mangle_name_by_path(cx.path + ["vtbl"]);
auto vtbl_name = mangle_internal_name_by_path(cx.ccx,
cx.path + ["vtbl"]);
auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl),
str::buf(vtbl_name));
llvm::LLVMSetInitializer(gvar, vtbl);
@ -7123,7 +7078,7 @@ fn trans_dtor(@local_ctxt cx,
&@ast::method dtor) -> ValueRef {
auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty);
let str s = mangle_name_by_path(cx.path + ["drop"]);
let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]);
let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
cx.ccx.item_ids.insert(dtor.node.id, llfn);
cx.ccx.item_symbols.insert(dtor.node.id, s);
@ -7516,25 +7471,29 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp,
}
}
let bool is_main = (str::eq(vec::top(path), "main") &&
!ccx.sess.get_opts().shared);
// Declare the function itself.
let str s = mangle_name_by_path(path);
let str s =
if (is_main) { "_rust_main" }
else { mangle_internal_name_by_path(ccx, path) };
let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
// Declare the global constant pair that points to it.
let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
register_fn_pair(ccx, ps, llpairty, llfn, id);
if (str::eq(vec::top(path), "main") &&
!ccx.sess.get_opts().shared) {
if (is_main) {
if (ccx.main_fn != none[ValueRef]) {
ccx.sess.span_err(sp, "multiple 'main' functions");
}
log #fmt("registering %s as main function for crate", ps);
llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage
as llvm::Linkage);
ccx.main_fn = some(llfn);
}
}
fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
@ -7565,7 +7524,7 @@ fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint {
alt (native_item.node) {
case (ast::native_item_ty(_,_)) {
cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
"actually a fn?!");
"actually a fn");
}
case (ast::native_item_fn(_, _, _, ?tps, _, _)) {
count = vec::len[ast::ty_param](tps);
@ -7594,13 +7553,13 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx,
// Declare the wrapper.
auto t = node_ann_type(ccx, ann);
auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
let str s = mangle_name_by_path(path);
let str s = mangle_internal_name_by_path(ccx, path);
let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s,
wrapper_type);
// Declare the global constant pair that points to it.
auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type);
let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id);
@ -7938,7 +7897,7 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) {
auto discrim_val = C_int(i as int);
auto p = wcx.path + [ident, variant.node.name, "discrim"];
auto s = mangle_name_by_type(ccx, p, ty::mk_int(ccx.tcx));
auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(),
str::buf(s));
@ -7957,8 +7916,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) {
// with consts.
auto v = C_int(1);
ccx.item_ids.insert(cid, v);
auto s = mangle_name_by_type(ccx, wcx.path + [name],
node_ann_type(ccx, ann));
auto s = mangle_exported_name(ccx, wcx.path + [name],
node_ann_type(ccx, ann));
ccx.item_symbols.insert(cid, s);
}
@ -8178,15 +8137,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
ret map;
}
fn crate_name(&@crate_ctxt ccx, &str deflt) -> str {
for (@ast::meta_item item in ccx.sess.get_metadata()) {
if (str::eq(item.node.name, "name")) {
ret item.node.value;
}
}
ret deflt;
}
// FIXME use hashed metadata instead of crate names once we have that
fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
let vec[ValueRef] subcrates = [];
@ -8199,10 +8149,9 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
i += 1;
}
vec::push[ValueRef](subcrates, C_int(0));
auto cname = crate_name(ccx, "__none__");
auto mapname;
if (ccx.sess.get_opts().shared) {
mapname = cname;
mapname = ccx.crate_meta_name;
} else {
mapname = "toplevel";
}
@ -8240,7 +8189,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate,
auto sha1s = map::mk_hashmap[ty::t,str](hasher, eqer);
auto abbrevs = map::mk_hashmap[ty::t,metadata::ty_abbrev](hasher, eqer);
auto short_names = map::mk_hashmap[ty::t,str](hasher, eqer);
auto sha = std::sha1::mk_sha1();
auto ccx = @rec(sess = sess,
llmod = llmod,
td = td,
@ -8252,6 +8201,10 @@ fn trans_crate(&session::session sess, &@ast::crate crate,
native_items = new_def_hash[@ast::native_item](),
item_symbols = new_def_hash[str](),
mutable main_fn = none[ValueRef],
crate_meta_name = crate_meta_name(sess, *crate, output),
crate_meta_vers = crate_meta_vers(sess, *crate),
crate_meta_extras_hash =
crate_meta_extras_hash(sha, *crate),
tag_sizes = tag_sizes,
discrims = new_def_hash[ValueRef](),
discrim_symbols = new_def_hash[str](),
@ -8263,7 +8216,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate,
lltypes = lltypes,
glues = glues,
names = namegen(0),
sha = std::sha1::mk_sha1(),
sha = sha,
type_sha1s = sha1s,
type_abbrevs = abbrevs,
type_short_names = short_names,

View File

@ -68,7 +68,7 @@ fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) {
case (ast::cdir_view_item(?vi)) {
walk_view_item(v, vi);
}
case (ast::cdir_meta(_)) {}
case (ast::cdir_meta(_,_)) {}
case (ast::cdir_syntax(_)) {}
case (ast::cdir_auth(_, _)) {}
}

View File

@ -19,6 +19,20 @@ fn dirname(path p) -> path {
ret str::substr(p, 0u, i as uint);
}
fn basename(path p) -> path {
let int i = str::rindex(p, os_fs::path_sep as u8);
if (i == -1) {
i = str::rindex(p, os_fs::alt_path_sep as u8);
if (i == -1) {
ret p;
}
}
auto len = str::byte_len(p);
if ((i+1) as uint >= len) { ret p; }
ret str::slice(p, i+1 as uint, len);
}
// FIXME: Need some typestate to avoid bounds check when len(pre) == 0
fn connect(path pre, path post) -> path {
auto len = str::byte_len(pre);

View File

@ -1,8 +1,10 @@
meta (name = "std",
desc = "Rust standard library",
vers = "0.1",
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
url = "http://rust-lang.org/src/std",
ver = "0.0.1");
url = "http://rust-lang.org/src/std");
meta (comment = "Rust standard library",
license = "BSD");
// Built-in types support modules.