@@ -2,116 +2,11 @@ use std::fs;
22use std:: path:: Path ;
33use std:: str;
44
5- use rustc_data_structures:: fx:: FxHashMap ;
65use serialize:: leb128;
76
87// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
9- const WASM_IMPORT_SECTION_ID : u8 = 2 ;
108const WASM_CUSTOM_SECTION_ID : u8 = 0 ;
119
12- const WASM_EXTERNAL_KIND_FUNCTION : u8 = 0 ;
13- const WASM_EXTERNAL_KIND_TABLE : u8 = 1 ;
14- const WASM_EXTERNAL_KIND_MEMORY : u8 = 2 ;
15- const WASM_EXTERNAL_KIND_GLOBAL : u8 = 3 ;
16-
17- /// Rewrite the module imports are listed from in a wasm module given the field
18- /// name to module name mapping in `import_map`.
19- ///
20- /// LLVM 6 which we're using right now doesn't have the ability to configure the
21- /// module a wasm symbol is import from. Rather all imported symbols come from
22- /// the bland `"env"` module unconditionally. Furthermore we'd *also* need
23- /// support in LLD for preserving these import modules, which it unfortunately
24- /// currently does not.
25- ///
26- /// This function is intended as a hack for now where we manually rewrite the
27- /// wasm output by LLVM to have the correct import modules listed. The
28- /// `#[link(wasm_import_module = "...")]` attribute in Rust translates to the
29- /// module that each symbol is imported from, so here we manually go through the
30- /// wasm file, decode it, rewrite imports, and then rewrite the wasm module.
31- ///
32- /// Support for this was added to LLVM in
33- /// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still
34- /// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168
35- pub fn rewrite_imports ( path : & Path , import_map : & FxHashMap < String , String > ) {
36- if import_map. is_empty ( ) {
37- return
38- }
39-
40- let wasm = fs:: read ( path) . expect ( "failed to read wasm output" ) ;
41- let mut ret = WasmEncoder :: new ( ) ;
42- ret. data . extend ( & wasm[ ..8 ] ) ;
43-
44- // skip the 8 byte wasm/version header
45- for ( id, raw) in WasmSections ( WasmDecoder :: new ( & wasm[ 8 ..] ) ) {
46- ret. byte ( id) ;
47- if id == WASM_IMPORT_SECTION_ID {
48- info ! ( "rewriting import section" ) ;
49- let data = rewrite_import_section (
50- & mut WasmDecoder :: new ( raw) ,
51- import_map,
52- ) ;
53- ret. bytes ( & data) ;
54- } else {
55- info ! ( "carry forward section {}, {} bytes long" , id, raw. len( ) ) ;
56- ret. bytes ( raw) ;
57- }
58- }
59-
60- fs:: write ( path, & ret. data ) . expect ( "failed to write wasm output" ) ;
61-
62- fn rewrite_import_section (
63- wasm : & mut WasmDecoder < ' _ > ,
64- import_map : & FxHashMap < String , String > ,
65- )
66- -> Vec < u8 >
67- {
68- let mut dst = WasmEncoder :: new ( ) ;
69- let n = wasm. u32 ( ) ;
70- dst. u32 ( n) ;
71- info ! ( "rewriting {} imports" , n) ;
72- for _ in 0 ..n {
73- rewrite_import_entry ( wasm, & mut dst, import_map) ;
74- }
75- return dst. data
76- }
77-
78- fn rewrite_import_entry ( wasm : & mut WasmDecoder < ' _ > ,
79- dst : & mut WasmEncoder ,
80- import_map : & FxHashMap < String , String > ) {
81- // More info about the binary format here is available at:
82- // https://webassembly.github.io/spec/core/binary/modules.html#import-section
83- //
84- // Note that you can also find the whole point of existence of this
85- // function here, where we map the `module` name to a different one if
86- // we've got one listed.
87- let module = wasm. str ( ) ;
88- let field = wasm. str ( ) ;
89- let new_module = if module == "env" {
90- import_map. get ( field) . map ( |s| & * * s) . unwrap_or ( module)
91- } else {
92- module
93- } ;
94- info ! ( "import rewrite ({} => {}) / {}" , module, new_module, field) ;
95- dst. str ( new_module) ;
96- dst. str ( field) ;
97- let kind = wasm. byte ( ) ;
98- dst. byte ( kind) ;
99- match kind {
100- WASM_EXTERNAL_KIND_FUNCTION => dst. u32 ( wasm. u32 ( ) ) ,
101- WASM_EXTERNAL_KIND_TABLE => {
102- dst. byte ( wasm. byte ( ) ) ; // element_type
103- dst. limits ( wasm. limits ( ) ) ;
104- }
105- WASM_EXTERNAL_KIND_MEMORY => dst. limits ( wasm. limits ( ) ) ,
106- WASM_EXTERNAL_KIND_GLOBAL => {
107- dst. byte ( wasm. byte ( ) ) ; // content_type
108- dst. bool ( wasm. bool ( ) ) ; // mutable
109- }
110- b => panic ! ( "unknown kind: {}" , b) ,
111- }
112- }
113- }
114-
11510/// Adds or augment the existing `producers` section to encode information about
11611/// the Rust compiler used to produce the wasm file.
11712pub fn add_producer_section (
@@ -266,15 +161,6 @@ impl<'a> WasmDecoder<'a> {
266161 let len = self . u32 ( ) ;
267162 str:: from_utf8 ( self . skip ( len as usize ) ) . unwrap ( )
268163 }
269-
270- fn bool ( & mut self ) -> bool {
271- self . byte ( ) == 1
272- }
273-
274- fn limits ( & mut self ) -> ( u32 , Option < u32 > ) {
275- let has_max = self . bool ( ) ;
276- ( self . u32 ( ) , if has_max { Some ( self . u32 ( ) ) } else { None } )
277- }
278164}
279165
280166struct WasmEncoder {
@@ -302,16 +188,4 @@ impl WasmEncoder {
302188 fn str ( & mut self , val : & str ) {
303189 self . bytes ( val. as_bytes ( ) )
304190 }
305-
306- fn bool ( & mut self , b : bool ) {
307- self . byte ( b as u8 ) ;
308- }
309-
310- fn limits ( & mut self , limits : ( u32 , Option < u32 > ) ) {
311- self . bool ( limits. 1 . is_some ( ) ) ;
312- self . u32 ( limits. 0 ) ;
313- if let Some ( c) = limits. 1 {
314- self . u32 ( c) ;
315- }
316- }
317191}
0 commit comments