From c47eb6eaa25dde27701c35689e94109435a7e5b7 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 16 Apr 2019 22:45:32 +0800 Subject: [PATCH 1/4] Fix corner cases. --- lib/singlepass-backend/src/codegen_x64.rs | 68 ++++++++++++++++------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index c574bfc146a..9663a47406d 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1230,11 +1230,27 @@ impl X64FunctionCode { if need_check { a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr)); - a.emit_add( - Size::S64, - Location::Imm32((offset + value_size) as u32), - Location::GPR(tmp_addr), - ); + match (offset as u32).checked_add(value_size as u32) { + Some(x) => { + a.emit_add( + Size::S64, + Location::Imm32(x), + Location::GPR(tmp_addr), + ); + } + None => { + a.emit_add( + Size::S64, + Location::Imm32(offset as u32), + Location::GPR(tmp_addr), + ); + a.emit_add( + Size::S64, + Location::Imm32(value_size as u32), + Location::GPR(tmp_addr), + ); + } + } a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr)); a.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr)); a.emit_conditional_trap(Condition::Above); @@ -1275,18 +1291,18 @@ impl X64FunctionCode { // Underflow. a.emit_mov(Size::S32, Location::Imm32(lower_bound), Location::GPR(tmp)); a.emit_mov(Size::S32, Location::GPR(tmp), Location::XMM(tmp_x)); - a.emit_vcmpltss(tmp_x, XMMOrMemory::XMM(reg), tmp_x); + a.emit_vcmpless(reg, XMMOrMemory::XMM(tmp_x), tmp_x); a.emit_mov(Size::S32, Location::XMM(tmp_x), Location::GPR(tmp)); - a.emit_cmp(Size::S32, Location::Imm32(1), Location::GPR(tmp)); - a.emit_jmp(Condition::Equal, trap); + a.emit_cmp(Size::S32, Location::Imm32(0), Location::GPR(tmp)); + a.emit_jmp(Condition::NotEqual, trap); // Overflow. a.emit_mov(Size::S32, Location::Imm32(upper_bound), Location::GPR(tmp)); a.emit_mov(Size::S32, Location::GPR(tmp), Location::XMM(tmp_x)); - a.emit_vcmpgtss(tmp_x, XMMOrMemory::XMM(reg), tmp_x); + a.emit_vcmpgess(reg, XMMOrMemory::XMM(tmp_x), tmp_x); a.emit_mov(Size::S32, Location::XMM(tmp_x), Location::GPR(tmp)); - a.emit_cmp(Size::S32, Location::Imm32(1), Location::GPR(tmp)); - a.emit_jmp(Condition::Equal, trap); + a.emit_cmp(Size::S32, Location::Imm32(0), Location::GPR(tmp)); + a.emit_jmp(Condition::NotEqual, trap); // NaN. a.emit_vcmpeqss(reg, XMMOrMemory::XMM(reg), tmp_x); @@ -1322,18 +1338,18 @@ impl X64FunctionCode { // Underflow. a.emit_mov(Size::S64, Location::Imm64(lower_bound), Location::GPR(tmp)); a.emit_mov(Size::S64, Location::GPR(tmp), Location::XMM(tmp_x)); - a.emit_vcmpltsd(tmp_x, XMMOrMemory::XMM(reg), tmp_x); + a.emit_vcmplesd(reg, XMMOrMemory::XMM(tmp_x), tmp_x); a.emit_mov(Size::S32, Location::XMM(tmp_x), Location::GPR(tmp)); - a.emit_cmp(Size::S32, Location::Imm32(1), Location::GPR(tmp)); - a.emit_jmp(Condition::Equal, trap); + a.emit_cmp(Size::S32, Location::Imm32(0), Location::GPR(tmp)); + a.emit_jmp(Condition::NotEqual, trap); // Overflow. a.emit_mov(Size::S64, Location::Imm64(upper_bound), Location::GPR(tmp)); a.emit_mov(Size::S64, Location::GPR(tmp), Location::XMM(tmp_x)); - a.emit_vcmpgtsd(tmp_x, XMMOrMemory::XMM(reg), tmp_x); + a.emit_vcmpgesd(reg, XMMOrMemory::XMM(tmp_x), tmp_x); a.emit_mov(Size::S32, Location::XMM(tmp_x), Location::GPR(tmp)); - a.emit_cmp(Size::S32, Location::Imm32(1), Location::GPR(tmp)); - a.emit_jmp(Condition::Equal, trap); + a.emit_cmp(Size::S32, Location::Imm32(0), Location::GPR(tmp)); + a.emit_jmp(Condition::NotEqual, trap); // NaN. a.emit_vcmpeqsd(reg, XMMOrMemory::XMM(reg), tmp_x); @@ -2697,16 +2713,28 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_out = self.machine.acquire_temp_gpr().unwrap(); let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - a.emit_mov(Size::S64, loc, Location::XMM(tmp_in)); + let real_in = match loc { + Location::Imm32(_) | Location::Imm64(_) => { + a.emit_mov(Size::S64, loc, Location::GPR(tmp_out)); + a.emit_mov(Size::S64, Location::GPR(tmp_out), Location::XMM(tmp_in)); + tmp_in + } + Location::XMM(x) => x, + _ => { + a.emit_mov(Size::S64, loc, Location::XMM(tmp_in)); + tmp_in + } + }; + Self::emit_f64_int_conv_check( a, &mut self.machine, - tmp_in, + real_in, -2147483649.0, 2147483648.0, ); - a.emit_cvttsd2si_32(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_cvttsd2si_32(XMMOrMemory::XMM(real_in), tmp_out); a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); self.machine.release_temp_xmm(tmp_in); From 0da2442be1a1933ab10c3822aefd8147ce054493 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 17 Apr 2019 02:10:36 +0800 Subject: [PATCH 2/4] Parse input in a single pass. --- lib/singlepass-backend/src/codegen.rs | 2 +- lib/singlepass-backend/src/codegen_x64.rs | 60 ++- lib/singlepass-backend/src/emitter_x64.rs | 24 ++ lib/singlepass-backend/src/parse.rs | 495 ++++++++++------------ 4 files changed, 274 insertions(+), 307 deletions(-) diff --git a/lib/singlepass-backend/src/codegen.rs b/lib/singlepass-backend/src/codegen.rs index 798dea114c0..586fd0851cb 100644 --- a/lib/singlepass-backend/src/codegen.rs +++ b/lib/singlepass-backend/src/codegen.rs @@ -23,7 +23,7 @@ pub trait FunctionCodeGenerator { fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>; fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError>; fn begin_body(&mut self) -> Result<(), CodegenError>; - fn feed_opcode(&mut self, op: Operator, module_info: &ModuleInfo) -> Result<(), CodegenError>; + fn feed_opcode(&mut self, op: &Operator, module_info: &ModuleInfo) -> Result<(), CodegenError>; fn finalize(&mut self) -> Result<(), CodegenError>; } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 9663a47406d..b0b2fdc2732 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1232,11 +1232,7 @@ impl X64FunctionCode { a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr)); match (offset as u32).checked_add(value_size as u32) { Some(x) => { - a.emit_add( - Size::S64, - Location::Imm32(x), - Location::GPR(tmp_addr), - ); + a.emit_add(Size::S64, Location::Imm32(x), Location::GPR(tmp_addr)); } None => { a.emit_add( @@ -1409,13 +1405,13 @@ impl FunctionCodeGenerator for X64FunctionCode { Ok(()) } - fn feed_opcode(&mut self, op: Operator, module_info: &ModuleInfo) -> Result<(), CodegenError> { + fn feed_opcode(&mut self, op: &Operator, module_info: &ModuleInfo) -> Result<(), CodegenError> { //println!("{:?} {}", op, self.value_stack.len()); let was_unreachable; if self.unreachable_depth > 0 { was_unreachable = true; - match op { + match *op { Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => { self.unreachable_depth += 1; } @@ -1442,7 +1438,7 @@ impl FunctionCodeGenerator for X64FunctionCode { } let a = self.assembler.as_mut().unwrap(); - match op { + match *op { Operator::GetGlobal { global_index } => { let global_index = global_index as usize; @@ -3344,7 +3340,7 @@ impl FunctionCodeGenerator for X64FunctionCode { self.value_stack.push((ret, LocalOrTemp::Temp)); a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret); } - Operator::I32Load { memarg } => { + Operator::I32Load { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0]; @@ -3369,7 +3365,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::F32Load { memarg } => { + Operator::F32Load { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0]; @@ -3394,7 +3390,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Load8U { memarg } => { + Operator::I32Load8U { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0]; @@ -3420,7 +3416,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Load8S { memarg } => { + Operator::I32Load8S { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0]; @@ -3446,7 +3442,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Load16U { memarg } => { + Operator::I32Load16U { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0]; @@ -3472,7 +3468,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Load16S { memarg } => { + Operator::I32Load16S { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0]; @@ -3498,7 +3494,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Store { memarg } => { + Operator::I32Store { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3523,7 +3519,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::F32Store { memarg } => { + Operator::F32Store { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3548,7 +3544,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Store8 { memarg } => { + Operator::I32Store8 { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3573,7 +3569,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I32Store16 { memarg } => { + Operator::I32Store16 { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3598,7 +3594,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load { memarg } => { + Operator::I64Load { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3623,7 +3619,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::F64Load { memarg } => { + Operator::F64Load { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0]; @@ -3648,7 +3644,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load8U { memarg } => { + Operator::I64Load8U { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3674,7 +3670,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load8S { memarg } => { + Operator::I64Load8S { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3700,7 +3696,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load16U { memarg } => { + Operator::I64Load16U { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3726,7 +3722,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load16S { memarg } => { + Operator::I64Load16S { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3752,7 +3748,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load32U { memarg } => { + Operator::I64Load32U { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3783,7 +3779,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Load32S { memarg } => { + Operator::I64Load32S { ref memarg } => { let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0]; @@ -3809,7 +3805,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Store { memarg } => { + Operator::I64Store { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3834,7 +3830,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::F64Store { memarg } => { + Operator::F64Store { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3859,7 +3855,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Store8 { memarg } => { + Operator::I64Store8 { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3884,7 +3880,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Store16 { memarg } => { + Operator::I64Store16 { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -3909,7 +3905,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, ); } - Operator::I64Store32 { memarg } => { + Operator::I64Store32 { ref memarg } => { let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let target_addr = @@ -4009,7 +4005,7 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_label(after); } - Operator::BrTable { table } => { + Operator::BrTable { ref table } => { let (targets, default_target) = table.read_table().unwrap(); let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 420a44123fe..8a949f8a5e6 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -502,18 +502,42 @@ impl Emitter for Assembler { (Size::S8, Location::Memory(src, disp), Location::GPR(dst)) => { dynasm!(self ; mov Rb(dst as u8), [Rq(src as u8) + disp]); } + (Size::S8, Location::Imm32(src), Location::GPR(dst)) => { + dynasm!(self ; mov Rb(dst as u8), src as i8); + } + (Size::S8, Location::Imm64(src), Location::GPR(dst)) => { + dynasm!(self ; mov Rb(dst as u8), src as i8); + } (Size::S8, Location::Imm32(src), Location::Memory(dst, disp)) => { dynasm!(self ; mov BYTE [Rq(dst as u8) + disp], src as i8); } + (Size::S8, Location::Imm64(src), Location::Memory(dst, disp)) => { + dynasm!(self ; mov BYTE [Rq(dst as u8) + disp], src as i8); + } (Size::S16, Location::GPR(src), Location::Memory(dst, disp)) => { dynasm!(self ; mov [Rq(dst as u8) + disp], Rw(src as u8)); } (Size::S16, Location::Memory(src, disp), Location::GPR(dst)) => { dynasm!(self ; mov Rw(dst as u8), [Rq(src as u8) + disp]); } + (Size::S16, Location::Imm32(src), Location::GPR(dst)) => { + dynasm!(self ; mov Rw(dst as u8), src as i16); + } + (Size::S16, Location::Imm64(src), Location::GPR(dst)) => { + dynasm!(self ; mov Rw(dst as u8), src as i16); + } (Size::S16, Location::Imm32(src), Location::Memory(dst, disp)) => { dynasm!(self ; mov WORD [Rq(dst as u8) + disp], src as i16); } + (Size::S16, Location::Imm64(src), Location::Memory(dst, disp)) => { + dynasm!(self ; mov WORD [Rq(dst as u8) + disp], src as i16); + } + (Size::S32, Location::Imm64(src), Location::GPR(dst)) => { + dynasm!(self ; mov Rd(dst as u8), src as i32); + } + (Size::S32, Location::Imm64(src), Location::Memory(dst, disp)) => { + dynasm!(self ; mov DWORD [Rq(dst as u8) + disp], src as i32); + } (Size::S32, Location::GPR(src), Location::XMM(dst)) => { dynasm!(self ; movd Rx(dst as u8), Rd(src as u8)); } diff --git a/lib/singlepass-backend/src/parse.rs b/lib/singlepass-backend/src/parse.rs index b198ea4c586..13b63311790 100644 --- a/lib/singlepass-backend/src/parse.rs +++ b/lib/singlepass-backend/src/parse.rs @@ -38,30 +38,6 @@ impl From for LoadError { } } -fn validate(bytes: &[u8]) -> Result<(), LoadError> { - let mut parser = wasmparser::ValidatingParser::new( - bytes, - Some(wasmparser::ValidatingParserConfig { - operator_config: wasmparser::OperatorValidatorConfig { - enable_threads: false, - enable_reference_types: false, - enable_simd: false, - enable_bulk_memory: false, - }, - mutable_global_imports: false, - }), - ); - - loop { - let state = parser.read(); - match *state { - wasmparser::ParserState::EndWasm => break Ok(()), - wasmparser::ParserState::Error(err) => Err(LoadError::Parse(err))?, - _ => {} - } - } -} - pub fn read_module< MCG: ModuleCodeGenerator, FCG: FunctionCodeGenerator, @@ -73,7 +49,6 @@ pub fn read_module< mcg: &mut MCG, compiler_config: &CompilerConfig, ) -> Result { - validate(wasm)?; let mut info = ModuleInfo { memories: Map::new(), globals: Map::new(), @@ -103,277 +78,251 @@ pub fn read_module< custom_sections: HashMap::new(), }; - let mut reader = ModuleReader::new(wasm)?; - - loop { - if reader.eof() { - return Ok(info); - } - - let section = reader.read()?; - - match section.code { - SectionCode::Type => { - let type_reader = section.get_type_section_reader()?; + let mut parser = wasmparser::ValidatingParser::new( + wasm, + Some(wasmparser::ValidatingParserConfig { + operator_config: wasmparser::OperatorValidatorConfig { + enable_threads: false, + enable_reference_types: false, + enable_simd: false, + enable_bulk_memory: false, + }, + mutable_global_imports: false, + }), + ); - for ty in type_reader { - let ty = ty?; - info.signatures.push(func_type_to_func_sig(ty)?); - } + let mut namespace_builder = Some(StringTableBuilder::new()); + let mut name_builder = Some(StringTableBuilder::new()); + let mut func_count: usize = ::std::usize::MAX; - mcg.feed_signatures(info.signatures.clone())?; + loop { + use wasmparser::ParserState; + let state = parser.read(); + match *state { + ParserState::EndWasm => break Ok(info), + ParserState::Error(err) => Err(LoadError::Parse(err))?, + ParserState::TypeSectionEntry(ref ty) => { + info.signatures.push(func_type_to_func_sig(ty)?); } - SectionCode::Import => { - let import_reader = section.get_import_section_reader()?; - let mut namespace_builder = StringTableBuilder::new(); - let mut name_builder = StringTableBuilder::new(); - - for import in import_reader { - let Import { module, field, ty } = import?; - - let namespace_index = namespace_builder.register(module); - let name_index = name_builder.register(field); - let import_name = ImportName { - namespace_index, - name_index, - }; - - match ty { - ImportSectionEntryType::Function(sigindex) => { - let sigindex = SigIndex::new(sigindex as usize); - info.imported_functions.push(import_name); - info.func_assoc.push(sigindex); - mcg.feed_import_function()?; - } - ImportSectionEntryType::Table(table_ty) => { - assert_eq!(table_ty.element_type, WpType::AnyFunc); - let table_desc = TableDescriptor { - element: ElementType::Anyfunc, - minimum: table_ty.limits.initial, - maximum: table_ty.limits.maximum, - }; - - info.imported_tables.push((import_name, table_desc)); - } - ImportSectionEntryType::Memory(memory_ty) => { - let mem_desc = MemoryDescriptor { - minimum: Pages(memory_ty.limits.initial), - maximum: memory_ty.limits.maximum.map(|max| Pages(max)), - shared: memory_ty.shared, - }; - info.imported_memories.push((import_name, mem_desc)); - } - ImportSectionEntryType::Global(global_ty) => { - let global_desc = GlobalDescriptor { - mutable: global_ty.mutable, - ty: wp_type_to_type(global_ty.content_type)?, - }; - info.imported_globals.push((import_name, global_desc)); - } + ParserState::ImportSectionEntry { module, field, ty } => { + let namespace_index = namespace_builder.as_mut().unwrap().register(module); + let name_index = name_builder.as_mut().unwrap().register(field); + let import_name = ImportName { + namespace_index, + name_index, + }; + + match ty { + ImportSectionEntryType::Function(sigindex) => { + let sigindex = SigIndex::new(sigindex as usize); + info.imported_functions.push(import_name); + info.func_assoc.push(sigindex); + mcg.feed_import_function()?; + } + ImportSectionEntryType::Table(table_ty) => { + assert_eq!(table_ty.element_type, WpType::AnyFunc); + let table_desc = TableDescriptor { + element: ElementType::Anyfunc, + minimum: table_ty.limits.initial, + maximum: table_ty.limits.maximum, + }; + + info.imported_tables.push((import_name, table_desc)); + } + ImportSectionEntryType::Memory(memory_ty) => { + let mem_desc = MemoryDescriptor { + minimum: Pages(memory_ty.limits.initial), + maximum: memory_ty.limits.maximum.map(|max| Pages(max)), + shared: memory_ty.shared, + }; + info.imported_memories.push((import_name, mem_desc)); + } + ImportSectionEntryType::Global(global_ty) => { + let global_desc = GlobalDescriptor { + mutable: global_ty.mutable, + ty: wp_type_to_type(global_ty.content_type)?, + }; + info.imported_globals.push((import_name, global_desc)); } } - - info.namespace_table = namespace_builder.finish(); - info.name_table = name_builder.finish(); } - SectionCode::Function => { - let func_decl_reader = section.get_function_section_reader()?; - - for sigindex in func_decl_reader { - let sigindex = sigindex?; - - let sigindex = SigIndex::new(sigindex as usize); - info.func_assoc.push(sigindex); - } - - mcg.feed_function_signatures(info.func_assoc.clone())?; + ParserState::FunctionSectionEntry(sigindex) => { + let sigindex = SigIndex::new(sigindex as usize); + info.func_assoc.push(sigindex); } - SectionCode::Table => { - let table_decl_reader = section.get_table_section_reader()?; - - for table_ty in table_decl_reader { - let table_ty = table_ty?; - - let table_desc = TableDescriptor { - element: ElementType::Anyfunc, - minimum: table_ty.limits.initial, - maximum: table_ty.limits.maximum, - }; - - info.tables.push(table_desc); - } + ParserState::TableSectionEntry(table_ty) => { + let table_desc = TableDescriptor { + element: ElementType::Anyfunc, + minimum: table_ty.limits.initial, + maximum: table_ty.limits.maximum, + }; + + info.tables.push(table_desc); } - SectionCode::Memory => { - let mem_decl_reader = section.get_memory_section_reader()?; - - for memory_ty in mem_decl_reader { - let memory_ty = memory_ty?; - - let mem_desc = MemoryDescriptor { - minimum: Pages(memory_ty.limits.initial), - maximum: memory_ty.limits.maximum.map(|max| Pages(max)), - shared: memory_ty.shared, - }; - - info.memories.push(mem_desc); - } + ParserState::MemorySectionEntry(memory_ty) => { + let mem_desc = MemoryDescriptor { + minimum: Pages(memory_ty.limits.initial), + maximum: memory_ty.limits.maximum.map(|max| Pages(max)), + shared: memory_ty.shared, + }; + + info.memories.push(mem_desc); } - SectionCode::Global => { - let global_decl_reader = section.get_global_section_reader()?; - - for global in global_decl_reader { - let global = global?; - - let desc = GlobalDescriptor { - mutable: global.ty.mutable, - ty: wp_type_to_type(global.ty.content_type)?, - }; - - let global_init = GlobalInit { - desc, - init: eval_init_expr(&global.init_expr)?, - }; + ParserState::ExportSectionEntry { field, kind, index } => { + let export_index = match kind { + ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)), + ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)), + ExternalKind::Memory => ExportIndex::Memory(MemoryIndex::new(index as usize)), + ExternalKind::Global => ExportIndex::Global(GlobalIndex::new(index as usize)), + }; + + info.exports.insert(field.to_string(), export_index); + } + ParserState::StartSectionEntry(start_index) => { + info.start_func = Some(FuncIndex::new(start_index as usize)); + } + ParserState::BeginFunctionBody { .. } => { + let id = func_count.wrapping_add(1); + func_count = id; + if func_count == 0 { + info.namespace_table = namespace_builder.take().unwrap().finish(); + info.name_table = name_builder.take().unwrap().finish(); + mcg.feed_signatures(info.signatures.clone())?; + mcg.feed_function_signatures(info.func_assoc.clone())?; + mcg.check_precondition(&info)?; + } - info.globals.push(global_init); + let fcg = mcg.next_function()?; + let sig = info + .signatures + .get( + *info + .func_assoc + .get(FuncIndex::new(id as usize + info.imported_functions.len())) + .unwrap(), + ) + .unwrap(); + for ret in sig.returns() { + fcg.feed_return(type_to_wp_type(*ret))?; + } + for param in sig.params() { + fcg.feed_param(type_to_wp_type(*param))?; } - } - SectionCode::Export => { - let export_reader = section.get_export_section_reader()?; - for export in export_reader { - let Export { field, kind, index } = export?; + let mut body_begun = false; - let export_index = match kind { - ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)), - ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)), - ExternalKind::Memory => { - ExportIndex::Memory(MemoryIndex::new(index as usize)) + loop { + let state = parser.read(); + match *state { + ParserState::Error(err) => return Err(LoadError::Parse(err)), + ParserState::FunctionBodyLocals { ref locals } => { + for &(count, ty) in locals.iter() { + fcg.feed_local(ty, count as usize)?; + } } - ExternalKind::Global => { - ExportIndex::Global(GlobalIndex::new(index as usize)) + ParserState::CodeOperator(ref op) => { + if !body_begun { + body_begun = true; + fcg.begin_body()?; + } + fcg.feed_opcode(op, &info)?; } - }; - - info.exports.insert(field.to_string(), export_index); + ParserState::EndFunctionBody => break, + _ => unreachable!(), + } } + fcg.finalize()?; } - SectionCode::Start => { - let start_index = section.get_start_section_content()?; - - info.start_func = Some(FuncIndex::new(start_index as usize)); - } - SectionCode::Element => { - let element_reader = section.get_element_section_reader()?; - - for element in element_reader { - let Element { kind, items } = element?; - - match kind { - ElementKind::Active { - table_index, - init_expr, - } => { - let table_index = TableIndex::new(table_index as usize); - let base = eval_init_expr(&init_expr)?; - let items_reader = items.get_items_reader()?; - - let elements: Vec<_> = items_reader - .into_iter() - .map(|res| res.map(|index| FuncIndex::new(index as usize))) - .collect::>()?; - - let table_init = TableInitializer { - table_index, - base, - elements, - }; - - info.elem_initializers.push(table_init); + ParserState::BeginActiveElementSectionEntry(table_index) => { + let table_index = TableIndex::new(table_index as usize); + let mut elements: Option> = None; + let mut base: Option = None; + + loop { + let state = parser.read(); + match *state { + ParserState::Error(err) => return Err(LoadError::Parse(err)), + ParserState::InitExpressionOperator(ref op) => { + base = Some(eval_init_expr(op)?) } - ElementKind::Passive(_ty) => { - return Err(BinaryReaderError { - message: "passive tables are not yet supported", - offset: -1isize as usize, - } - .into()); + ParserState::ElementSectionEntryBody(ref _elements) => { + elements = Some( + _elements + .iter() + .cloned() + .map(|index| FuncIndex::new(index as usize)) + .collect(), + ); } + ParserState::BeginInitExpressionBody + | ParserState::EndInitExpressionBody => {} + ParserState::EndElementSectionEntry => break, + _ => unreachable!(), } } + + let table_init = TableInitializer { + table_index, + base: base.unwrap(), + elements: elements.unwrap(), + }; + + info.elem_initializers.push(table_init); } - SectionCode::Code => { - let mut code_reader = section.get_code_section_reader()?; - if code_reader.get_count() as usize > info.func_assoc.len() { - return Err(BinaryReaderError { - message: "code_reader.get_count() > info.func_assoc.len()", - offset: ::std::usize::MAX, - } - .into()); - } - mcg.check_precondition(&info)?; - for i in 0..code_reader.get_count() { - let item = code_reader.read()?; - let fcg = mcg.next_function()?; - let sig = info - .signatures - .get( - *info - .func_assoc - .get(FuncIndex::new(i as usize + info.imported_functions.len())) - .unwrap(), - ) - .unwrap(); - for ret in sig.returns() { - fcg.feed_return(type_to_wp_type(*ret))?; - } - for param in sig.params() { - fcg.feed_param(type_to_wp_type(*param))?; - } - for local in item.get_locals_reader()? { - let (count, ty) = local?; - fcg.feed_local(ty, count as usize)?; - } - fcg.begin_body()?; - for op in item.get_operators_reader()? { - let op = op?; - fcg.feed_opcode(op, &info)?; + ParserState::BeginActiveDataSectionEntry(memory_index) => { + let memory_index = MemoryIndex::new(memory_index as usize); + let mut base: Option = None; + let mut data: Vec = vec![]; + + loop { + let state = parser.read(); + match *state { + ParserState::Error(err) => return Err(LoadError::Parse(err)), + ParserState::InitExpressionOperator(ref op) => { + base = Some(eval_init_expr(op)?) + } + ParserState::DataSectionEntryBodyChunk(chunk) => { + data = chunk.to_vec(); + } + ParserState::BeginInitExpressionBody + | ParserState::EndInitExpressionBody => {} + ParserState::BeginDataSectionEntryBody(_) + | ParserState::EndDataSectionEntryBody => {} + ParserState::EndDataSectionEntry => break, + _ => unreachable!(), } - fcg.finalize()?; } + + let data_init = DataInitializer { + memory_index, + base: base.unwrap(), + data, + }; + info.data_initializers.push(data_init); } - SectionCode::Data => { - let data_reader = section.get_data_section_reader()?; - - for data in data_reader { - let Data { kind, data } = data?; - - match kind { - DataKind::Active { - memory_index, - init_expr, - } => { - let memory_index = MemoryIndex::new(memory_index as usize); - let base = eval_init_expr(&init_expr)?; - - let data_init = DataInitializer { - memory_index, - base, - data: data.to_vec(), - }; - - info.data_initializers.push(data_init); - } - DataKind::Passive => { - return Err(BinaryReaderError { - message: "passive memories are not yet supported", - offset: -1isize as usize, - } - .into()); + ParserState::BeginGlobalSectionEntry(ty) => { + let init = loop { + let state = parser.read(); + match *state { + ParserState::Error(err) => return Err(LoadError::Parse(err)), + ParserState::InitExpressionOperator(ref op) => { + break eval_init_expr(op)?; } + ParserState::BeginInitExpressionBody => {} + _ => unreachable!(), } - } + }; + let desc = GlobalDescriptor { + mutable: ty.mutable, + ty: wp_type_to_type(ty.content_type)?, + }; + + let global_init = GlobalInit { desc, init }; + + info.globals.push(global_init); } - SectionCode::DataCount => {} - SectionCode::Custom { .. } => {} + + _ => {} } } } @@ -403,7 +352,7 @@ pub fn type_to_wp_type(ty: Type) -> WpType { } } -fn func_type_to_func_sig(func_ty: FuncType) -> Result { +fn func_type_to_func_sig(func_ty: &FuncType) -> Result { assert_eq!(func_ty.form, WpType::Func); Ok(FuncSig::new( @@ -422,10 +371,8 @@ fn func_type_to_func_sig(func_ty: FuncType) -> Result Result { - let mut reader = expr.get_operators_reader(); - let (op, offset) = reader.read_with_offset()?; - Ok(match op { +fn eval_init_expr(op: &Operator) -> Result { + Ok(match *op { Operator::GetGlobal { global_index } => { Initializer::GetGlobal(ImportedGlobalIndex::new(global_index as usize)) } @@ -440,7 +387,7 @@ fn eval_init_expr(expr: &InitExpr) -> Result { _ => { return Err(BinaryReaderError { message: "init expr evaluation failed: unsupported opcode", - offset, + offset: -1isize as usize, }); } }) From e71da1cdf1d133d2cb8f91b4a19b246817a7cec1 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 18 Apr 2019 02:28:08 +0800 Subject: [PATCH 3/4] Some documentation on the code generator. --- lib/singlepass-backend/src/codegen.rs | 25 +++++++++++++++ lib/singlepass-backend/src/codegen_x64.rs | 39 ++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen.rs b/lib/singlepass-backend/src/codegen.rs index 586fd0851cb..fd43f1a8687 100644 --- a/lib/singlepass-backend/src/codegen.rs +++ b/lib/singlepass-backend/src/codegen.rs @@ -6,24 +6,49 @@ use wasmer_runtime_core::{ }; use wasmparser::{Operator, Type as WpType}; +/// The module-scope code generator trait. pub trait ModuleCodeGenerator { + /// Verifies that the module satisfies a precondition before generating code for it. + /// This method is called just before the first call to `next_function`. fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError>; + + /// Creates a new function and returns the function-scope code generator for it. fn next_function(&mut self) -> Result<&mut FCG, CodegenError>; + + /// Finalizes code generation, returning runtime structures. fn finalize(self, module_info: &ModuleInfo) -> Result<(PC, FR), CodegenError>; + + /// Sets signatures. fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError>; + + /// Sets function signatures. fn feed_function_signatures( &mut self, assoc: Map, ) -> Result<(), CodegenError>; + + /// Adds an import function. fn feed_import_function(&mut self) -> Result<(), CodegenError>; } +/// The function-scope code generator trait. pub trait FunctionCodeGenerator { + /// Sets the return type. fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError>; + + /// Adds a parameter to the function. fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>; + + /// Adds `n` locals to the function. fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError>; + + /// Called before the first call to `feed_opcode`. fn begin_body(&mut self) -> Result<(), CodegenError>; + + /// Called for each operator. fn feed_opcode(&mut self, op: &Operator, module_info: &ModuleInfo) -> Result<(), CodegenError>; + + /// Finalizes the function. fn finalize(&mut self) -> Result<(), CodegenError>; } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b0b2fdc2732..f0bf448fb3a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -27,6 +27,7 @@ use wasmer_runtime_core::{ use wasmparser::{Operator, Type as WpType}; lazy_static! { + /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = { let mut assembler = Assembler::new().unwrap(); let offset = assembler.offset(); @@ -467,6 +468,9 @@ impl ModuleCodeGenerator( a: &mut Assembler, m: &mut Machine, @@ -697,6 +706,7 @@ impl X64FunctionCode { m.release_temp_xmm(tmp1); } + /// I32 binary operation with both operands popped from the virtual stack. fn emit_binop_i32( a: &mut Assembler, m: &mut Machine, @@ -735,6 +745,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I64 binary operation with both operands popped from the virtual stack. fn emit_binop_i64( a: &mut Assembler, m: &mut Machine, @@ -773,6 +784,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I32 comparison with `loc_b` from input. fn emit_cmpop_i32_dynamic_b( a: &mut Assembler, m: &mut Machine, @@ -803,6 +815,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I32 comparison with both operands popped from the virtual stack. fn emit_cmpop_i32( a: &mut Assembler, m: &mut Machine, @@ -813,6 +826,7 @@ impl X64FunctionCode { Self::emit_cmpop_i32_dynamic_b(a, m, value_stack, c, loc_b); } + /// I64 comparison with `loc_b` from input. fn emit_cmpop_i64_dynamic_b( a: &mut Assembler, m: &mut Machine, @@ -843,6 +857,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I64 comparison with both operands popped from the virtual stack. fn emit_cmpop_i64( a: &mut Assembler, m: &mut Machine, @@ -853,6 +868,7 @@ impl X64FunctionCode { Self::emit_cmpop_i64_dynamic_b(a, m, value_stack, c, loc_b); } + /// I32 `lzcnt`/`tzcnt`/`popcnt` with operand popped from the virtual stack. fn emit_xcnt_i32( a: &mut Assembler, m: &mut Machine, @@ -891,6 +907,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I64 `lzcnt`/`tzcnt`/`popcnt` with operand popped from the virtual stack. fn emit_xcnt_i64( a: &mut Assembler, m: &mut Machine, @@ -929,6 +946,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I32 shift with both operands popped from the virtual stack. fn emit_shift_i32( a: &mut Assembler, m: &mut Machine, @@ -949,6 +967,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// I64 shift with both operands popped from the virtual stack. fn emit_shift_i64( a: &mut Assembler, m: &mut Machine, @@ -969,6 +988,7 @@ impl X64FunctionCode { value_stack.push((ret, LocalOrTemp::Temp)); } + /// Floating point (AVX) binary operation with both operands popped from the virtual stack. fn emit_fp_binop_avx( a: &mut Assembler, m: &mut Machine, @@ -983,6 +1003,7 @@ impl X64FunctionCode { Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret); } + /// Floating point (AVX) comparison with both operands popped from the virtual stack. fn emit_fp_cmpop_avx( a: &mut Assembler, m: &mut Machine, @@ -998,6 +1019,7 @@ impl X64FunctionCode { a.emit_and(Size::S32, Location::Imm32(1), ret); // FIXME: Why? } + /// Floating point (AVX) binary operation with both operands popped from the virtual stack. fn emit_fp_unop_avx( a: &mut Assembler, m: &mut Machine, @@ -1011,7 +1033,9 @@ impl X64FunctionCode { Self::emit_relaxed_avx(a, m, f, loc, loc, ret); } - // This function must not use RAX before `cb` is called. + /// Emits a System V call sequence. + /// + /// This function must not use RAX before `cb` is called. fn emit_call_sysv, F: FnOnce(&mut Assembler)>( a: &mut Assembler, m: &mut Machine, @@ -1167,6 +1191,7 @@ impl X64FunctionCode { } } + /// Emits a System V call sequence, specialized for labels as the call target. fn emit_call_sysv_label>( a: &mut Assembler, m: &mut Machine, @@ -1176,6 +1201,7 @@ impl X64FunctionCode { Self::emit_call_sysv(a, m, |a| a.emit_call_label(label), params) } + /// Emits a memory operation. fn emit_memory_op( module_info: &ModuleInfo, a: &mut Assembler, @@ -1189,6 +1215,7 @@ impl X64FunctionCode { let tmp_base = m.acquire_temp_gpr().unwrap(); let tmp_bound = m.acquire_temp_gpr().unwrap(); + // Loads both base and bound into temporary registers. a.emit_mov( Size::S64, Location::Memory( @@ -1215,8 +1242,11 @@ impl X64FunctionCode { Location::Memory(tmp_base, LocalMemory::offset_base() as i32), Location::GPR(tmp_base), ); + + // Adds base to bound so `tmp_bound` now holds the end of linear memory. a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_bound)); + // If the memory is dynamic, we need to do bound checking at runtime. let mem_desc = match MemoryIndex::new(0).local_or_import(module_info) { LocalOrImport::Local(local_mem_index) => &module_info.memories[local_mem_index], LocalOrImport::Import(import_mem_index) => { @@ -1230,6 +1260,8 @@ impl X64FunctionCode { if need_check { a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr)); + + // This branch is used for emitting "faster" code for the special case of (offset + value_size) not exceeding u32 range. match (offset as u32).checked_add(value_size as u32) { Some(x) => { a.emit_add(Size::S64, Location::Imm32(x), Location::GPR(tmp_addr)); @@ -1247,6 +1279,8 @@ impl X64FunctionCode { ); } } + + // Trap if the end address of the requested area is above that of the linear memory. a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr)); a.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr)); a.emit_conditional_trap(Condition::Above); @@ -1254,6 +1288,7 @@ impl X64FunctionCode { m.release_temp_gpr(tmp_bound); + // Calculates the real address, and loads from it. a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr)); a.emit_add( Size::S64, @@ -1268,6 +1303,7 @@ impl X64FunctionCode { m.release_temp_gpr(tmp_addr); } + // Checks for underflow/overflow/nan before IxxTrunc{U/S}F32. fn emit_f32_int_conv_check( a: &mut Assembler, m: &mut Machine, @@ -1315,6 +1351,7 @@ impl X64FunctionCode { m.release_temp_gpr(tmp); } + // Checks for underflow/overflow/nan before IxxTrunc{U/S}F64. fn emit_f64_int_conv_check( a: &mut Assembler, m: &mut Machine, From 61f31ae7e8f697b8d05756e6a86ea452486fe0bd Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Wed, 17 Apr 2019 15:17:16 -0700 Subject: [PATCH 4/4] Fix lint (just two lines) --- lib/singlepass-backend/src/codegen.rs | 2 +- lib/singlepass-backend/src/codegen_x64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/src/codegen.rs b/lib/singlepass-backend/src/codegen.rs index fd43f1a8687..b484a17f02f 100644 --- a/lib/singlepass-backend/src/codegen.rs +++ b/lib/singlepass-backend/src/codegen.rs @@ -14,7 +14,7 @@ pub trait ModuleCodeGenerator Result<&mut FCG, CodegenError>; - + /// Finalizes code generation, returning runtime structures. fn finalize(self, module_info: &ModuleInfo) -> Result<(PC, FR), CodegenError>; diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f0bf448fb3a..7b214bbb6bf 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1034,7 +1034,7 @@ impl X64FunctionCode { } /// Emits a System V call sequence. - /// + /// /// This function must not use RAX before `cb` is called. fn emit_call_sysv, F: FnOnce(&mut Assembler)>( a: &mut Assembler,