@@ -3,14 +3,15 @@ mod wasm_ld;
33use std:: borrow:: Cow ;
44use std:: convert:: Infallible ;
55use std:: ffi:: { OsStr , OsString } ;
6- use std:: fmt:: Write ;
6+ use std:: fs:: File ;
7+ use std:: io:: { BufWriter , Write } ;
78use std:: path:: Path ;
89use std:: process:: { self , Command } ;
910use std:: { env, fs} ;
1011
1112use hashbrown:: { HashMap , HashSet } ;
1213use itertools:: { Itertools , Position } ;
13- use js_bindgen_ld_shared:: CustomSectionParser ;
14+ use js_bindgen_ld_shared:: { CustomSectionParser , ReadFile } ;
1415use wasm_encoder:: { EntityType , ImportSection , Module , RawSection , Section } ;
1516use wasmparser:: { Encoding , Parser , Payload , TypeRef } ;
1617
@@ -148,11 +149,14 @@ fn process_object(
148149 // ensures freshness:
149150 // https://doc.rust-lang.org/1.92.0/nightly-rustc/cargo/core/compiler/fingerprint/index.html#fingerprints-and-unithashs
150151 if !asm_path. exists ( ) {
151- let asm_object = js_bindgen_ld_shared:: assembly_to_object ( arch_str, assembly)
152+ let mut asm_file = BufWriter :: new (
153+ File :: create ( & asm_path) . expect ( "output assembly object should be writable" ) ,
154+ ) ;
155+
156+ js_bindgen_ld_shared:: assembly_to_object ( arch_str, assembly, & mut asm_file)
152157 . expect ( "compiling assembly should be valid" ) ;
153158
154- fs:: write ( & asm_path, asm_object)
155- . expect ( "writing assembly object file should succeed" ) ;
159+ asm_file. into_inner ( ) . unwrap ( ) . sync_all ( ) . unwrap ( ) ;
156160 }
157161
158162 add_args. push ( asm_path. into ( ) ) ;
@@ -166,7 +170,7 @@ fn post_processing(output_path: &Path, main_memory: MainMemory<'_>) {
166170 // Unfortunately we don't receive the final output path adjustments Cargo makes.
167171 // So for the JS file we just figure it out ourselves.
168172 let package = env:: var_os ( "CARGO_CRATE_NAME" ) . expect ( "`CARGO_CRATE_NAME` should be present" ) ;
169- let wasm_input = fs :: read ( output_path) . expect ( "output file should be readable" ) ;
173+ let wasm_input = ReadFile :: new ( output_path) . expect ( "output file should be readable" ) ;
170174 let mut wasm_output = Vec :: new ( ) ;
171175
172176 let mut found_import: HashMap < & str , HashMap < & str , & str > > = HashMap :: new ( ) ;
@@ -396,12 +400,15 @@ fn post_processing(output_path: &Path, main_memory: MainMemory<'_>) {
396400 "missing JS embed: {expected_embed:?}"
397401 ) ;
398402
399- fs:: write ( output_path, wasm_output) . expect ( "output Wasm file should be writable" ) ;
400-
401- let mut js_output = String :: new ( ) ;
403+ let mut js_output = BufWriter :: new (
404+ File :: create ( output_path. with_file_name ( package) . with_extension ( "js" ) )
405+ . expect ( "output JS file should be writable" ) ,
406+ ) ;
402407
403408 // Create our `WebAssembly.Memory`.
404- js_output. push_str ( "const memory = new WebAssembly.Memory({ " ) ;
409+ js_output
410+ . write_all ( b"const memory = new WebAssembly.Memory({ " )
411+ . unwrap ( ) ;
405412
406413 if memory. memory64 {
407414 write ! ( js_output, "initial: {}n" , memory. initial) . unwrap ( ) ;
@@ -418,18 +425,18 @@ fn post_processing(output_path: &Path, main_memory: MainMemory<'_>) {
418425 }
419426
420427 if memory. memory64 {
421- js_output. push_str ( ", address: 'i64'" ) ;
428+ js_output. write_all ( b ", address: 'i64'") . unwrap ( ) ;
422429 }
423430
424431 if memory. shared {
425- js_output. push_str ( ", shared: true" ) ;
432+ js_output. write_all ( b ", shared: true") . unwrap ( ) ;
426433 }
427434
428- js_output. push_str ( " })\n \n " ) ;
435+ js_output. write_all ( b " })\n \n ") . unwrap ( ) ;
429436
430437 // Output requested embedded JS.
431438 if !found_embed. is_empty ( ) {
432- js_output. push_str ( "const jsEmbed = {\n " ) ;
439+ js_output. write_all ( b "const jsEmbed = {\n ") . unwrap ( ) ;
433440
434441 for ( package, embeds) in found_embed {
435442 writeln ! ( js_output, "\t {package}: {{" ) . unwrap ( ) ;
@@ -438,25 +445,27 @@ fn post_processing(output_path: &Path, main_memory: MainMemory<'_>) {
438445 write ! ( js_output, "\t \t \" {name}\" : " ) . unwrap ( ) ;
439446
440447 for ( position, line) in js. lines ( ) . with_position ( ) {
441- js_output. push_str ( line) ;
448+ js_output. write_all ( line. as_bytes ( ) ) . unwrap ( ) ;
442449
443450 if let Position :: First | Position :: Middle = position {
444- js_output. push_str ( "\n \t \t " ) ;
451+ js_output. write_all ( b "\n \t \t ") . unwrap ( ) ;
445452 }
446453 }
447454
448- js_output. push_str ( ",\n " ) ;
455+ js_output. write_all ( b ",\n ") . unwrap ( ) ;
449456 }
450457
451- js_output. push_str ( "\t },\n " ) ;
458+ js_output. write_all ( b "\t },\n ") . unwrap ( ) ;
452459 }
453460
454- js_output. push_str ( "}\n \n " ) ;
461+ js_output. write_all ( b "}\n \n ") . unwrap ( ) ;
455462 }
456463
457464 // Create our `importObject`.
458- js_output. push_str ( "export const importObject = {\n " ) ;
459- js_output. push_str ( "\t js_bindgen: { memory },\n " ) ;
465+ js_output
466+ . write_all ( b"export const importObject = {\n " )
467+ . unwrap ( ) ;
468+ js_output. write_all ( b"\t js_bindgen: { memory },\n " ) . unwrap ( ) ;
460469
461470 for ( module, names) in found_import {
462471 writeln ! ( js_output, "\t {module}: {{" ) . unwrap ( ) ;
@@ -465,24 +474,27 @@ fn post_processing(output_path: &Path, main_memory: MainMemory<'_>) {
465474 write ! ( js_output, "\t \t \" {name}\" : " ) . unwrap ( ) ;
466475
467476 for ( position, line) in js. lines ( ) . with_position ( ) {
468- js_output. push_str ( line) ;
477+ js_output. write_all ( line. as_bytes ( ) ) . unwrap ( ) ;
469478
470479 if let Position :: First | Position :: Middle = position {
471- js_output. push_str ( "\n \t \t " ) ;
480+ js_output. write_all ( b "\n \t \t ") . unwrap ( ) ;
472481 }
473482 }
474483
475- js_output. push_str ( ",\n " ) ;
484+ js_output. write_all ( b ",\n ") . unwrap ( ) ;
476485 }
477486
478- js_output. push_str ( "\t },\n " ) ;
487+ js_output. write_all ( b "\t },\n ") . unwrap ( ) ;
479488 }
480489
481- js_output. push_str ( "}\n " ) ;
490+ js_output. write_all ( b "}\n ") . unwrap ( ) ;
482491
483- fs:: write (
484- output_path. with_file_name ( package) . with_extension ( "js" ) ,
485- js_output,
486- )
487- . expect ( "output JS file should be writable" ) ;
492+ js_output. into_inner ( ) . unwrap ( ) . sync_all ( ) . unwrap ( ) ;
493+
494+ // We could write into the file directly, but `wasm-encoder` doesn't support
495+ // `io::Write`: https://github.com/bytecodealliance/wasm-tools/issues/778.
496+ //
497+ // When it does, we should rename the old file and write to a new file. This way
498+ // we can keep parsing and writing at the same time without allocating memory.
499+ fs:: write ( output_path, wasm_output) . expect ( "output Wasm file should be writable" ) ;
488500}
0 commit comments