Skip to content

Commit 8551566

Browse files
committed
rustc: Add a #[wasm_import_module] attribute
This commit adds a new attribute to the Rust compiler specific to the wasm target (and no other targets). The `#[wasm_import_module]` attribute is used to specify the module that a name is imported from, and is used like so: #[wasm_import_module = "./foo.js"] extern { fn some_js_function(); } Here the import of the symbol `some_js_function` is tagged with the `./foo.js` module in the wasm output file. Wasm-the-format includes two fields on all imports, a module and a field. The field is the symbol name (`some_js_function` above) and the module has historically unconditionally been `"env"`. I'm not sure if this `"env"` convention has asm.js or LLVM roots, but regardless we'd like the ability to configure it! The proposed ES module integration with wasm (aka a wasm module is "just another ES module") requires that the import module of wasm imports is interpreted as an ES module import, meaning that you'll need to encode paths, NPM packages, etc. As a result, we'll need this to be something other than `"env"`! Unfortunately neither our version of LLVM nor LLD supports custom import modules (aka anything not `"env"`). My hope is that by the time LLVM 7 is released both will have support, but in the meantime this commit adds some primitive encoding/decoding of wasm files to the compiler. This way rustc postprocesses the wasm module that LLVM emits to ensure it's got all the imports we'd like to have in it. Eventually I'd ideally like to unconditionally require this attribute to be placed on all `extern { ... }` blocks. For now though it seemed prudent to add it as an unstable attribute, so for now it's not required (as that'd force usage of a feature gate). Hopefully it doesn't take too long to "stabilize" this! cc rust-lang-nursery/rust-wasm#29
1 parent 8c4ff22 commit 8551566

26 files changed

+559
-45
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ define_dep_nodes!( <'tcx>
590590
[] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
591591
[] AllTraitImplementations(CrateNum),
592592

593+
[] DllimportForeignItems(CrateNum),
593594
[] IsDllimportForeignItem(DefId),
594595
[] IsStaticallyIncludedForeignItem(DefId),
595596
[] NativeLibraryKind(DefId),
@@ -648,6 +649,9 @@ define_dep_nodes!( <'tcx>
648649
[] GetSymbolExportLevel(DefId),
649650

650651
[input] Features,
652+
653+
[] WasmImportModuleMap(CrateNum),
654+
[] ForeignModules(CrateNum),
651655
);
652656

653657
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {

src/librustc/hir/check_attr.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ enum Target {
2525
Struct,
2626
Union,
2727
Enum,
28+
ForeignMod,
2829
Other,
2930
}
3031

@@ -35,6 +36,7 @@ impl Target {
3536
hir::ItemStruct(..) => Target::Struct,
3637
hir::ItemUnion(..) => Target::Union,
3738
hir::ItemEnum(..) => Target::Enum,
39+
hir::ItemForeignMod(..) => Target::ForeignMod,
3840
_ => Target::Other,
3941
}
4042
}
@@ -55,14 +57,33 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
5557
.emit();
5658
}
5759

60+
let mut has_wasm_import_module = false;
5861
for attr in &item.attrs {
59-
if let Some(name) = attr.name() {
60-
if name == "inline" {
61-
self.check_inline(attr, item, target)
62+
if attr.check_name("inline") {
63+
self.check_inline(attr, item, target)
64+
} else if attr.check_name("wasm_import_module") {
65+
has_wasm_import_module = true;
66+
if attr.value_str().is_none() {
67+
self.tcx.sess.span_err(attr.span, "\
68+
must be of the form #[wasm_import_module = \"...\"]");
69+
}
70+
if target != Target::ForeignMod {
71+
self.tcx.sess.span_err(attr.span, "\
72+
must only be attached to foreign modules");
6273
}
6374
}
6475
}
6576

77+
if target == Target::ForeignMod &&
78+
!has_wasm_import_module &&
79+
self.tcx.sess.target.target.arch == "wasm32" &&
80+
false // FIXME: eventually enable this warning when stable
81+
{
82+
self.tcx.sess.span_warn(item.span, "\
83+
must have a #[wasm_import_module = \"...\"] attribute, this \
84+
will become a hard error before too long");
85+
}
86+
6687
self.check_repr(item, target);
6788
}
6889

src/librustc/ich/impls_cstore.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ impl_stable_hash_for!(struct middle::cstore::NativeLibrary {
3333
kind,
3434
name,
3535
cfg,
36-
foreign_items
36+
foreign_module
37+
});
38+
39+
impl_stable_hash_for!(struct middle::cstore::ForeignModule {
40+
foreign_items,
41+
def_id
3742
});
3843

3944
impl_stable_hash_for!(enum middle::cstore::LinkagePreference {

src/librustc/middle/cstore.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ pub struct NativeLibrary {
132132
pub kind: NativeLibraryKind,
133133
pub name: Symbol,
134134
pub cfg: Option<ast::MetaItem>,
135+
pub foreign_module: Option<DefId>,
136+
}
137+
138+
#[derive(Clone, Hash, RustcEncodable, RustcDecodable)]
139+
pub struct ForeignModule {
135140
pub foreign_items: Vec<DefId>,
141+
pub def_id: DefId,
136142
}
137143

138144
pub enum LoadedMacro {

src/librustc/ty/maps/config.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::native_libraries<'tcx> {
418418
}
419419
}
420420

421+
impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> {
422+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
423+
format!("looking up the foreign modules of a linked crate")
424+
}
425+
}
426+
421427
impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> {
422428
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
423429
format!("looking up the plugin registrar for a crate")
@@ -681,6 +687,18 @@ impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> {
681687
}
682688
}
683689

690+
impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> {
691+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
692+
format!("wasm import module map")
693+
}
694+
}
695+
696+
impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> {
697+
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
698+
format!("wasm import module map")
699+
}
700+
}
701+
684702
macro_rules! impl_disk_cacheable_query(
685703
($query_name:ident, |$key:tt| $cond:expr) => {
686704
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {

src/librustc/ty/maps/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use infer::canonical::{Canonical, QueryResult};
1818
use lint;
1919
use middle::borrowck::BorrowCheckResult;
2020
use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
21-
ExternBodyNestedBodies};
21+
ExternBodyNestedBodies, ForeignModule};
2222
use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody};
2323
use middle::privacy::AccessLevels;
2424
use middle::reachable::ReachableSet;
@@ -315,6 +315,9 @@ define_maps! { <'tcx>
315315

316316

317317
[] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
318+
319+
[] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>,
320+
318321
[] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
319322
[] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
320323
[] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator,
@@ -326,6 +329,8 @@ define_maps! { <'tcx>
326329
[] fn all_trait_implementations: AllTraitImplementations(CrateNum)
327330
-> Lrc<Vec<DefId>>,
328331

332+
[] fn dllimport_foreign_items: DllimportForeignItems(CrateNum)
333+
-> Lrc<FxHashSet<DefIndex>>,
329334
[] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
330335
[] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
331336
[] fn native_library_kind: NativeLibraryKind(DefId)
@@ -417,6 +422,8 @@ define_maps! { <'tcx>
417422
-> usize,
418423

419424
[] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
425+
[] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
426+
-> Lrc<FxHashMap<DefIndex, String>>,
420427
}
421428

422429
//////////////////////////////////////////////////////////////////////

src/librustc/ty/maps/plumbing.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
883883
force!(all_trait_implementations, krate!());
884884
}
885885

886+
DepKind::DllimportForeignItems => {
887+
force!(dllimport_foreign_items, krate!());
888+
}
886889
DepKind::IsDllimportForeignItem => {
887890
force!(is_dllimport_foreign_item, def_id!());
888891
}
@@ -935,6 +938,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
935938

936939
DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
937940
DepKind::Features => { force!(features_query, LOCAL_CRATE); }
941+
DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); }
942+
DepKind::ForeignModules => { force!(foreign_modules, krate!()); }
938943
}
939944

940945
true

src/librustc_metadata/creader.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
1313
use cstore::{self, CStore, CrateSource, MetadataBlob};
1414
use locator::{self, CratePaths};
15-
use native_libs::relevant_lib;
1615
use schema::CrateRoot;
1716
use rustc_data_structures::sync::Lrc;
1817

@@ -231,7 +230,7 @@ impl<'a> CrateLoader<'a> {
231230
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
232231
.collect();
233232

234-
let mut cmeta = cstore::CrateMetadata {
233+
let cmeta = cstore::CrateMetadata {
235234
name,
236235
extern_crate: Cell::new(None),
237236
def_path_table: Lrc::new(def_path_table),
@@ -251,25 +250,8 @@ impl<'a> CrateLoader<'a> {
251250
rlib,
252251
rmeta,
253252
},
254-
// Initialize this with an empty set. The field is populated below
255-
// after we were able to deserialize its contents.
256-
dllimport_foreign_items: FxHashSet(),
257253
};
258254

259-
let dllimports: FxHashSet<_> = cmeta
260-
.root
261-
.native_libraries
262-
.decode((&cmeta, self.sess))
263-
.filter(|lib| relevant_lib(self.sess, lib) &&
264-
lib.kind == cstore::NativeLibraryKind::NativeUnknown)
265-
.flat_map(|lib| {
266-
assert!(lib.foreign_items.iter().all(|def_id| def_id.krate == cnum));
267-
lib.foreign_items.into_iter().map(|def_id| def_id.index)
268-
})
269-
.collect();
270-
271-
cmeta.dllimport_foreign_items = dllimports;
272-
273255
let cmeta = Lrc::new(cmeta);
274256
self.cstore.set_crate_data(cnum, cmeta.clone());
275257
(cnum, cmeta)

src/librustc_metadata/cstore.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
2020
use rustc::session::{Session, CrateDisambiguator};
2121
use rustc_back::PanicStrategy;
2222
use rustc_data_structures::indexed_vec::IndexVec;
23-
use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap};
23+
use rustc::util::nodemap::{FxHashMap, NodeMap};
2424

2525
use std::cell::{RefCell, Cell};
2626
use rustc_data_structures::sync::Lrc;
@@ -31,7 +31,7 @@ use syntax_pos;
3131

3232
pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
3333
pub use rustc::middle::cstore::NativeLibraryKind::*;
34-
pub use rustc::middle::cstore::{CrateSource, LibSource};
34+
pub use rustc::middle::cstore::{CrateSource, LibSource, ForeignModule};
3535

3636
pub use cstore_impl::{provide, provide_extern};
3737

@@ -85,8 +85,6 @@ pub struct CrateMetadata {
8585
pub source: CrateSource,
8686

8787
pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
88-
// Foreign items imported from a dylib (Windows only)
89-
pub dllimport_foreign_items: FxHashSet<DefIndex>,
9088
}
9189

9290
pub struct CStore {

src/librustc_metadata/cstore_impl.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use cstore;
1212
use encoder;
1313
use link_args;
1414
use native_libs;
15+
use foreign_modules;
1516
use schema;
1617

1718
use rustc::ty::maps::QueryConfig;
@@ -194,6 +195,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
194195
Lrc::new(reachable_non_generics)
195196
}
196197
native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
198+
foreign_modules => { Lrc::new(cdata.get_foreign_modules(tcx.sess)) }
197199
plugin_registrar_fn => {
198200
cdata.root.plugin_registrar_fn.map(|index| {
199201
DefId { krate: def_id.krate, index }
@@ -221,9 +223,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
221223
Lrc::new(result)
222224
}
223225

224-
is_dllimport_foreign_item => {
225-
cdata.is_dllimport_foreign_item(def_id.index)
226-
}
227226
visibility => { cdata.get_visibility(def_id.index) }
228227
dep_kind => { cdata.dep_kind.get() }
229228
crate_name => { cdata.name }
@@ -297,13 +296,28 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
297296
tcx.native_libraries(id.krate)
298297
.iter()
299298
.filter(|lib| native_libs::relevant_lib(&tcx.sess, lib))
300-
.find(|l| l.foreign_items.contains(&id))
299+
.find(|lib| {
300+
let fm_id = match lib.foreign_module {
301+
Some(id) => id,
302+
None => return false,
303+
};
304+
tcx.foreign_modules(id.krate)
305+
.iter()
306+
.find(|m| m.def_id == fm_id)
307+
.expect("failed to find foreign module")
308+
.foreign_items
309+
.contains(&id)
310+
})
301311
.map(|l| l.kind)
302312
},
303313
native_libraries: |tcx, cnum| {
304314
assert_eq!(cnum, LOCAL_CRATE);
305315
Lrc::new(native_libs::collect(tcx))
306316
},
317+
foreign_modules: |tcx, cnum| {
318+
assert_eq!(cnum, LOCAL_CRATE);
319+
Lrc::new(foreign_modules::collect(tcx))
320+
},
307321
link_args: |tcx, cnum| {
308322
assert_eq!(cnum, LOCAL_CRATE);
309323
Lrc::new(link_args::collect(tcx))

src/librustc_metadata/decoder.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// Decoding metadata from a single crate's metadata
1212

13-
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
13+
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
1414
use schema::*;
1515

1616
use rustc_data_structures::sync::Lrc;
@@ -1034,6 +1034,10 @@ impl<'a, 'tcx> CrateMetadata {
10341034
self.root.native_libraries.decode((self, sess)).collect()
10351035
}
10361036

1037+
pub fn get_foreign_modules(&self, sess: &Session) -> Vec<ForeignModule> {
1038+
self.root.foreign_modules.decode((self, sess)).collect()
1039+
}
1040+
10371041
pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> {
10381042
self.root
10391043
.dylib_dependency_formats
@@ -1096,10 +1100,6 @@ impl<'a, 'tcx> CrateMetadata {
10961100
}
10971101
}
10981102

1099-
pub fn is_dllimport_foreign_item(&self, id: DefIndex) -> bool {
1100-
self.dllimport_foreign_items.contains(&id)
1101-
}
1102-
11031103
pub fn fn_sig(&self,
11041104
id: DefIndex,
11051105
tcx: TyCtxt<'a, 'tcx, 'tcx>)

src/librustc_metadata/encoder.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use isolated_encoder::IsolatedEncoder;
1414
use schema::*;
1515

1616
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
17-
EncodedMetadata};
17+
EncodedMetadata, ForeignModule};
1818
use rustc::hir::def::CtorKind;
1919
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
2020
use rustc::hir::map::definitions::DefPathTable;
@@ -416,6 +416,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
416416
());
417417
let native_lib_bytes = self.position() - i;
418418

419+
let foreign_modules = self.tracked(
420+
IsolatedEncoder::encode_foreign_modules,
421+
());
422+
419423
// Encode codemap
420424
i = self.position();
421425
let codemap = self.encode_codemap();
@@ -478,6 +482,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
478482
lang_items,
479483
lang_items_missing,
480484
native_libraries,
485+
foreign_modules,
481486
codemap,
482487
def_path_table,
483488
impls,
@@ -1334,6 +1339,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
13341339
self.lazy_seq(used_libraries.iter().cloned())
13351340
}
13361341

1342+
fn encode_foreign_modules(&mut self, _: ()) -> LazySeq<ForeignModule> {
1343+
let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE);
1344+
self.lazy_seq(foreign_modules.iter().cloned())
1345+
}
1346+
13371347
fn encode_crate_deps(&mut self, _: ()) -> LazySeq<CrateDep> {
13381348
let crates = self.tcx.crates();
13391349

0 commit comments

Comments
 (0)