diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp index d1095a7819d4a..55f11665f6d0b 100644 --- a/src/librustc_binaryen/BinaryenWrapper.cpp +++ b/src/librustc_binaryen/BinaryenWrapper.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include "s2wasm.h" @@ -24,6 +25,7 @@ using namespace wasm; struct BinaryenRustModule { BufferWithRandomAccess buffer; + std::string sourceMapJSON; }; struct BinaryenRustModuleOptions { @@ -36,6 +38,7 @@ struct BinaryenRustModuleOptions { bool ignoreUnknownSymbols; bool debugInfo; std::string startFunction; + std::string sourceMapUrl; BinaryenRustModuleOptions() : globalBase(0), @@ -46,7 +49,8 @@ struct BinaryenRustModuleOptions { importMemory(false), ignoreUnknownSymbols(false), debugInfo(false), - startFunction("") + startFunction(""), + sourceMapUrl("") {} }; @@ -73,6 +77,12 @@ BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options, options->startFunction = start; } +extern "C" void +BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options, + char *sourceMapUrl) { + options->sourceMapUrl = sourceMapUrl; +} + extern "C" void BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options, uint64_t stack) { @@ -106,12 +116,20 @@ BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options, { WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug); writer.setNamesSection(options->debugInfo); - // FIXME: support source maps? - // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl); + + std::unique_ptr sourceMapStream = nullptr; + { + sourceMapStream = make_unique(); + writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl); + } // FIXME: support symbol maps? // writer.setSymbolMap(symbolMap); writer.write(); + + if (sourceMapStream) { + ret->sourceMapJSON = sourceMapStream->str(); + } } return ret.release(); } @@ -126,6 +144,16 @@ BinaryenRustModuleLen(const BinaryenRustModule *M) { return M->buffer.size(); } +extern "C" const char* +BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) { + return M->sourceMapJSON.data(); +} + +extern "C" size_t +BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) { + return M->sourceMapJSON.length(); +} + extern "C" void BinaryenRustModuleFree(BinaryenRustModule *M) { delete M; diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs index 6c7feb6a7a9d3..36174e11ba04a 100644 --- a/src/librustc_binaryen/lib.rs +++ b/src/librustc_binaryen/lib.rs @@ -51,6 +51,15 @@ impl Module { slice::from_raw_parts(ptr, len) } } + + /// Returns the data of the source map JSON. + pub fn source_map(&self) -> &[u8] { + unsafe { + let ptr = BinaryenRustModuleSourceMapPtr(self.ptr); + let len = BinaryenRustModuleSourceMapLen(self.ptr); + slice::from_raw_parts(ptr, len) + } + } } impl Drop for Module { @@ -94,6 +103,15 @@ impl ModuleOptions { self } + /// Configures a `sourceMappingURL` custom section value for the module. + pub fn source_map_url(&mut self, url: &str) -> &mut Self { + let url = CString::new(url).unwrap(); + unsafe { + BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr()); + } + self + } + /// Configures how much stack is initially allocated for the module. 1MB is /// probably good enough for now. pub fn stack(&mut self, amt: u64) -> &mut Self { @@ -130,6 +148,8 @@ extern { -> *mut BinaryenRustModule; fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8; fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize; + fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8; + fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize; fn BinaryenRustModuleFree(module: *mut BinaryenRustModule); fn BinaryenRustModuleOptionsCreate() @@ -138,6 +158,8 @@ extern { debuginfo: bool); fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions, start: *const libc::c_char); + fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions, + sourceMapUrl: *const libc::c_char); fn BinaryenRustModuleOptionsSetStackAllocation( module: *mut BinaryenRustModuleOptions, stack: u64, diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index a013af7a4600e..7a194a37c9c55 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -748,7 +748,10 @@ unsafe fn codegen(cgcx: &CodegenContext, if asm2wasm && config.emit_obj { let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); - binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out); + let suffix = ".wasm.map"; // FIXME use target suffix + let map = cgcx.output_filenames.path(OutputType::Exe) + .with_extension(&suffix[1..]); + binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map); timeline.record("binaryen"); if !config.emit_asm { @@ -795,7 +798,8 @@ unsafe fn codegen(cgcx: &CodegenContext, fn binaryen_assemble(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, - object: &Path) { + object: &Path, + map: &Path) { use rustc_binaryen::{Module, ModuleOptions}; let input = fs::read(&assembly).and_then(|contents| { @@ -804,6 +808,8 @@ fn binaryen_assemble(cgcx: &CodegenContext, let mut options = ModuleOptions::new(); if cgcx.debuginfo != config::NoDebugInfo { options.debuginfo(true); + let map_file_name = map.file_name().unwrap(); + options.source_map_url(map_file_name.to_str().unwrap()); } if cgcx.crate_types.contains(&config::CrateTypeExecutable) { options.start("main"); @@ -815,7 +821,13 @@ fn binaryen_assemble(cgcx: &CodegenContext, .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) }); let err = assembled.and_then(|binary| { - fs::write(&object, binary.data()) + fs::write(&object, binary.data()).and_then(|()| { + if cgcx.debuginfo != config::NoDebugInfo { + fs::write(map, binary.source_map()) + } else { + Ok(()) + } + }) }); if let Err(e) = err { handler.err(&format!("failed to run binaryen assembler: {}", e));