diff --git a/lib/compiler-singlepass/src/address_map.rs b/lib/compiler-singlepass/src/address_map.rs new file mode 100644 index 000000000..5253066a6 --- /dev/null +++ b/lib/compiler-singlepass/src/address_map.rs @@ -0,0 +1,23 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + +use wasmer_compiler::{FunctionAddressMap, FunctionBodyData, InstructionAddressMap, SourceLoc}; + +pub fn get_function_address_map<'data>( + instructions: Vec, + data: &FunctionBodyData<'data>, + body_len: usize, +) -> FunctionAddressMap { + // Generate artificial srcloc for function start/end to identify boundary + // within module. It will wrap around if byte code is larger than 4 GB. + let start_srcloc = SourceLoc::new(data.module_offset as u32); + let end_srcloc = SourceLoc::new((data.module_offset + data.data.len()) as u32); + + FunctionAddressMap { + instructions, + start_srcloc, + end_srcloc, + body_offset: 0, + body_len, + } +} diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index 150c57886..dd0a06d6f 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -1,3 +1,4 @@ +use crate::address_map::get_function_address_map; use crate::{common_decl::*, config::Singlepass, emitter_x64::*, machine::Machine, x64_decl::*}; use dynasmrt::{x64::Assembler, DynamicLabel}; use smallvec::{smallvec, SmallVec}; @@ -8,8 +9,8 @@ use wasmer_compiler::wasmparser::{ }; use wasmer_compiler::{ CompiledFunction, CompiledFunctionFrameInfo, CustomSection, CustomSectionProtection, - FunctionBody, Relocation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, - TrapInformation, + FunctionBody, FunctionBodyData, InstructionAddressMap, Relocation, RelocationKind, + RelocationTarget, SectionBody, SectionIndex, SourceLoc, TrapInformation, }; use wasmer_types::{ entity::{EntityRef, PrimaryMap, SecondaryMap}, @@ -80,6 +81,12 @@ pub struct FuncGen<'a> { /// A set of special labels for trapping. special_labels: SpecialLabelSet, + + /// The source location for the current operator + src_loc: u32, + + /// All the InstructionAddressMap + instructions_address_map: Vec, } struct SpecialLabelSet { @@ -251,6 +258,11 @@ struct I2O1 { } impl<'a> FuncGen<'a> { + /// Set the source location of the Wasm to the given offset + pub fn set_srcloc(&mut self, offset: u32) { + self.src_loc = offset; + } + fn get_location_released(&mut self, loc: Location) -> Location { self.machine.release_locations(&mut self.assembler, &[loc]); loc @@ -306,6 +318,11 @@ impl<'a> FuncGen<'a> { for i in begin..end { self.trap_table.offset_to_code.insert(i, code); } + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: begin, + code_len: end - begin, + }); ret } @@ -313,6 +330,11 @@ impl<'a> FuncGen<'a> { fn mark_address_with_trap_code(&mut self, code: TrapCode) { let offset = self.assembler.get_offset().0; self.trap_table.offset_to_code.insert(offset, code); + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); } /// Canonicalizes the floating point value at `input` into `output`. @@ -379,16 +401,28 @@ impl<'a> FuncGen<'a> { Location::Imm64(_) | Location::Imm32(_) => { self.assembler.emit_mov(sz, loc, Location::GPR(GPR::RCX)); // must not be used during div (rax, rdx) self.mark_trappable(); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); self.trap_table .offset_to_code - .insert(self.assembler.get_offset().0, TrapCode::IntegerOverflow); + .insert(offset, TrapCode::IntegerOverflow); op(&mut self.assembler, sz, Location::GPR(GPR::RCX)); } _ => { self.mark_trappable(); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); self.trap_table .offset_to_code - .insert(self.assembler.get_offset().0, TrapCode::IntegerOverflow); + .insert(offset, TrapCode::IntegerOverflow); op(&mut self.assembler, sz, loc); } } @@ -1473,16 +1507,28 @@ impl<'a> FuncGen<'a> { ); self.assembler.emit_label(trap_overflow); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); self.trap_table .offset_to_code - .insert(self.assembler.get_offset().0, TrapCode::IntegerOverflow); + .insert(offset, TrapCode::IntegerOverflow); self.assembler.emit_ud2(); self.assembler.emit_label(trap_badconv); - self.trap_table.offset_to_code.insert( - self.assembler.get_offset().0, - TrapCode::BadConversionToInteger, - ); + + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); + self.trap_table + .offset_to_code + .insert(offset, TrapCode::BadConversionToInteger); self.assembler.emit_ud2(); self.assembler.emit_label(end); @@ -1622,16 +1668,27 @@ impl<'a> FuncGen<'a> { ); self.assembler.emit_label(trap_overflow); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); self.trap_table .offset_to_code - .insert(self.assembler.get_offset().0, TrapCode::IntegerOverflow); + .insert(offset, TrapCode::IntegerOverflow); self.assembler.emit_ud2(); self.assembler.emit_label(trap_badconv); - self.trap_table.offset_to_code.insert( - self.assembler.get_offset().0, - TrapCode::BadConversionToInteger, - ); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); + self.trap_table + .offset_to_code + .insert(offset, TrapCode::BadConversionToInteger); self.assembler.emit_ud2(); self.assembler.emit_label(end); @@ -1819,6 +1876,8 @@ impl<'a> FuncGen<'a> { trap_table: TrapTable::default(), relocations: vec![], special_labels, + src_loc: 0, + instructions_address_map: vec![], }; fg.emit_head()?; Ok(fg) @@ -6128,10 +6187,15 @@ impl<'a> FuncGen<'a> { } Operator::Unreachable => { self.mark_trappable(); - self.trap_table.offset_to_code.insert( - self.assembler.get_offset().0, - TrapCode::UnreachableCodeReached, - ); + let offset = self.assembler.get_offset().0; + self.instructions_address_map.push(InstructionAddressMap { + srcloc: SourceLoc::new(self.src_loc), + code_offset: offset, + code_len: 2, // TODO: Check this length + }); + self.trap_table + .offset_to_code + .insert(offset, TrapCode::UnreachableCodeReached); self.assembler.emit_ud2(); self.unreachable_depth = 1; } @@ -8125,7 +8189,7 @@ impl<'a> FuncGen<'a> { Ok(()) } - pub fn finalize(mut self) -> CompiledFunction { + pub fn finalize(mut self, data: &FunctionBodyData) -> CompiledFunction { // Generate actual code for special labels. self.assembler .emit_label(self.special_labels.integer_division_by_zero); @@ -8153,6 +8217,11 @@ impl<'a> FuncGen<'a> { // Notify the assembler backend to generate necessary code at end of function. self.assembler.finalize_function(); + + let body_len = self.assembler.get_offset().0; + let instructions_address_map = self.instructions_address_map; + let address_map = get_function_address_map(instructions_address_map, data, body_len); + CompiledFunction { body: FunctionBody { body: self.assembler.finalize().unwrap().to_vec(), @@ -8170,7 +8239,7 @@ impl<'a> FuncGen<'a> { trap_code: code, }) .collect(), - ..Default::default() + address_map, }, } } diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 2c90a6d3a..72107a9f3 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -106,11 +106,12 @@ impl Compiler for SinglepassCompiler { .map_err(to_compile_error)?; while generator.has_control_frames() { + generator.set_srcloc(reader.original_position() as u32); let op = reader.read_operator().map_err(to_compile_error)?; generator.feed_operator(op).map_err(to_compile_error)?; } - Ok(generator.finalize()) + Ok(generator.finalize(&input)) }) .collect::, CompileError>>()? .into_iter() diff --git a/lib/compiler-singlepass/src/lib.rs b/lib/compiler-singlepass/src/lib.rs index e549e7d15..202c0b9da 100644 --- a/lib/compiler-singlepass/src/lib.rs +++ b/lib/compiler-singlepass/src/lib.rs @@ -8,6 +8,7 @@ //! Compared to Cranelift and LLVM, Singlepass compiles much faster but has worse //! runtime performance. +mod address_map; mod codegen_x64; mod common_decl; mod compiler;