Merge pull request #774 from lars-t-hansen/jump_tables

Generalize information about compiled code
This commit is contained in:
Lars T Hansen
2019-06-01 12:24:41 +02:00
committed by GitHub
12 changed files with 166 additions and 73 deletions

View File

@@ -14,7 +14,7 @@
//! relocations to a `RelocSink` trait object. Relocations are less frequent than the //! relocations to a `RelocSink` trait object. Relocations are less frequent than the
//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe. //! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
use super::{Addend, CodeOffset, CodeSink, Reloc}; use super::{Addend, CodeInfo, CodeOffset, CodeSink, Reloc};
use crate::ir::{ExternalName, JumpTable, SourceLoc, TrapCode}; use crate::ir::{ExternalName, JumpTable, SourceLoc, TrapCode};
use core::ptr::write_unaligned; use core::ptr::write_unaligned;
@@ -30,12 +30,14 @@ use core::ptr::write_unaligned;
/// Note that `MemoryCodeSink` writes multi-byte values in the native byte order of the host. This /// Note that `MemoryCodeSink` writes multi-byte values in the native byte order of the host. This
/// is not the right thing to do for cross compilation. /// is not the right thing to do for cross compilation.
pub struct MemoryCodeSink<'a> { pub struct MemoryCodeSink<'a> {
/// Pointer to start of sink's preallocated memory.
data: *mut u8, data: *mut u8,
/// Offset is isize because its major consumer needs it in that form.
offset: isize, offset: isize,
/// Size of the machine code portion of output
pub code_size: isize,
relocs: &'a mut RelocSink, relocs: &'a mut RelocSink,
traps: &'a mut TrapSink, traps: &'a mut TrapSink,
/// Information about the generated code and read-only data.
pub info: CodeInfo,
} }
impl<'a> MemoryCodeSink<'a> { impl<'a> MemoryCodeSink<'a> {
@@ -47,7 +49,12 @@ impl<'a> MemoryCodeSink<'a> {
Self { Self {
data, data,
offset: 0, offset: 0,
code_size: 0, info: CodeInfo {
code_size: 0,
jumptables_size: 0,
rodata_size: 0,
total_size: 0,
},
relocs, relocs,
traps, traps,
} }
@@ -75,40 +82,35 @@ pub trait TrapSink {
fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode); fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode);
} }
impl<'a> MemoryCodeSink<'a> {
fn write<T>(&mut self, x: T) {
unsafe {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
write_unaligned(self.data.offset(self.offset) as *mut T, x);
self.offset += std::mem::size_of::<T>() as isize;
}
}
}
impl<'a> CodeSink for MemoryCodeSink<'a> { impl<'a> CodeSink for MemoryCodeSink<'a> {
fn offset(&self) -> CodeOffset { fn offset(&self) -> CodeOffset {
self.offset as CodeOffset self.offset as CodeOffset
} }
fn put1(&mut self, x: u8) { fn put1(&mut self, x: u8) {
unsafe { self.write(x);
write_unaligned(self.data.offset(self.offset), x);
}
self.offset += 1;
} }
fn put2(&mut self, x: u16) { fn put2(&mut self, x: u16) {
unsafe { self.write(x);
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
write_unaligned(self.data.offset(self.offset) as *mut u16, x);
}
self.offset += 2;
} }
fn put4(&mut self, x: u32) { fn put4(&mut self, x: u32) {
unsafe { self.write(x);
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
write_unaligned(self.data.offset(self.offset) as *mut u32, x);
}
self.offset += 4;
} }
fn put8(&mut self, x: u64) { fn put8(&mut self, x: u64) {
unsafe { self.write(x);
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
write_unaligned(self.data.offset(self.offset) as *mut u64, x);
}
self.offset += 8;
} }
fn reloc_ebb(&mut self, rel: Reloc, ebb_offset: CodeOffset) { fn reloc_ebb(&mut self, rel: Reloc, ebb_offset: CodeOffset) {
@@ -131,8 +133,17 @@ impl<'a> CodeSink for MemoryCodeSink<'a> {
self.traps.trap(ofs, srcloc, code); self.traps.trap(ofs, srcloc, code);
} }
fn begin_jumptables(&mut self) {
self.info.code_size = self.offset();
}
fn begin_rodata(&mut self) { fn begin_rodata(&mut self) {
self.code_size = self.offset; self.info.jumptables_size = self.offset() - self.info.code_size;
}
fn end_codegen(&mut self) {
self.info.rodata_size = self.offset() - self.info.jumptables_size;
self.info.total_size = self.offset();
} }
} }

View File

@@ -33,6 +33,8 @@ pub enum Reloc {
Abs8, Abs8,
/// x86 PC-relative 4-byte /// x86 PC-relative 4-byte
X86PCRel4, X86PCRel4,
/// x86 PC-relative 4-byte offset to trailing rodata
X86PCRelRodata4,
/// x86 call to PC-relative 4-byte /// x86 call to PC-relative 4-byte
X86CallPCRel4, X86CallPCRel4,
/// x86 call to PLT-relative 4-byte /// x86 call to PLT-relative 4-byte
@@ -55,6 +57,7 @@ impl fmt::Display for Reloc {
Reloc::Abs4 => write!(f, "Abs4"), Reloc::Abs4 => write!(f, "Abs4"),
Reloc::Abs8 => write!(f, "Abs8"), Reloc::Abs8 => write!(f, "Abs8"),
Reloc::X86PCRel4 => write!(f, "PCRel4"), Reloc::X86PCRel4 => write!(f, "PCRel4"),
Reloc::X86PCRelRodata4 => write!(f, "PCRelRodata4"),
Reloc::X86CallPCRel4 => write!(f, "CallPCRel4"), Reloc::X86CallPCRel4 => write!(f, "CallPCRel4"),
Reloc::X86CallPLTRel4 => write!(f, "CallPLTRel4"), Reloc::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
Reloc::X86GOTPCRel4 => write!(f, "GOTPCRel4"), Reloc::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
@@ -63,6 +66,38 @@ impl fmt::Display for Reloc {
} }
} }
/// Container for information about a vector of compiled code and its supporting read-only data.
///
/// The code starts at offset 0 and is followed optionally by relocatable jump tables and copyable
/// (raw binary) read-only data. Any padding between sections is always part of the section that
/// precedes the boundary between the sections.
#[derive(PartialEq)]
pub struct CodeInfo {
/// Number of bytes of machine code (the code starts at offset 0).
pub code_size: CodeOffset,
/// Number of bytes of jumptables.
pub jumptables_size: CodeOffset,
/// Number of bytes of rodata.
pub rodata_size: CodeOffset,
/// Number of bytes in total.
pub total_size: CodeOffset,
}
impl CodeInfo {
/// Offset of any relocatable jump tables, or equal to rodata if there are no jump tables.
pub fn jumptables(&self) -> CodeOffset {
self.code_size
}
/// Offset of any copyable read-only data, or equal to total_size if there are no rodata.
pub fn rodata(&self) -> CodeOffset {
self.code_size + self.jumptables_size
}
}
/// Abstract interface for adding bytes to the code segment. /// Abstract interface for adding bytes to the code segment.
/// ///
/// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations /// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations
@@ -95,8 +130,14 @@ pub trait CodeSink {
/// Add trap information for the current offset. /// Add trap information for the current offset.
fn trap(&mut self, _: TrapCode, _: SourceLoc); fn trap(&mut self, _: TrapCode, _: SourceLoc);
/// Code output is complete, read-only data may follow. /// Machine code output is complete, jump table data may follow.
fn begin_jumptables(&mut self);
/// Jump table output is complete, raw read-only data may follow.
fn begin_rodata(&mut self); fn begin_rodata(&mut self);
/// Read-only data output is complete, we're done.
fn end_codegen(&mut self);
} }
/// Report a bad encoding error. /// Report a bad encoding error.
@@ -127,7 +168,7 @@ where
} }
} }
sink.begin_rodata(); sink.begin_jumptables();
// output jump tables // output jump tables
for (jt, jt_data) in func.jump_tables.iter() { for (jt, jt_data) in func.jump_tables.iter() {
@@ -137,4 +178,9 @@ where
sink.put4(rel_offset as u32) sink.put4(rel_offset as u32)
} }
} }
sink.begin_rodata();
// TODO: No read-only data (constant pools) at this time.
sink.end_codegen();
} }

View File

@@ -27,7 +27,7 @@
//! ebb23: //! ebb23:
//! ``` //! ```
use crate::binemit::CodeOffset; use crate::binemit::{CodeInfo, CodeOffset};
use crate::cursor::{Cursor, FuncCursor}; use crate::cursor::{Cursor, FuncCursor};
use crate::ir::{Function, InstructionData, Opcode}; use crate::ir::{Function, InstructionData, Opcode};
use crate::isa::{EncInfo, TargetIsa}; use crate::isa::{EncInfo, TargetIsa};
@@ -40,7 +40,7 @@ use log::debug;
/// Relax branches and compute the final layout of EBB headers in `func`. /// Relax branches and compute the final layout of EBB headers in `func`.
/// ///
/// Fill in the `func.offsets` table so the function is ready for binary emission. /// Fill in the `func.offsets` table so the function is ready for binary emission.
pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<CodeOffset> { pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
let _tt = timing::relax_branches(); let _tt = timing::relax_branches();
let encinfo = isa.encoding_info(); let encinfo = isa.encoding_info();
@@ -109,6 +109,9 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
} }
} }
let code_size = offset;
let jumptables = offset;
for (jt, jt_data) in func.jump_tables.iter() { for (jt, jt_data) in func.jump_tables.iter() {
func.jt_offsets[jt] = offset; func.jt_offsets[jt] = offset;
// TODO: this should be computed based on the min size needed to hold // TODO: this should be computed based on the min size needed to hold
@@ -116,7 +119,19 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
offset += jt_data.len() as u32 * 4; offset += jt_data.len() as u32 * 4;
} }
Ok(offset) let jumptables_size = offset - jumptables;
let rodata = offset;
// TODO: Once we have constant pools we'll do some processing here to update offset.
let rodata_size = offset - rodata;
Ok(CodeInfo {
code_size,
jumptables_size,
rodata_size,
total_size: offset,
})
} }
/// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any /// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any

View File

@@ -10,7 +10,7 @@
//! single ISA instance. //! single ISA instance.
use crate::binemit::{ use crate::binemit::{
relax_branches, shrink_instructions, CodeOffset, MemoryCodeSink, RelocSink, TrapSink, relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, TrapSink,
}; };
use crate::dce::do_dce; use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree; use crate::dominator_tree::DominatorTree;
@@ -93,20 +93,21 @@ impl Context {
/// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
/// needed, so it provides a safe interface. /// needed, so it provides a safe interface.
/// ///
/// Returns the size of the function's code and the size of the read-only data. /// Returns information about the function's code and read-only data.
pub fn compile_and_emit( pub fn compile_and_emit(
&mut self, &mut self,
isa: &TargetIsa, isa: &TargetIsa,
mem: &mut Vec<u8>, mem: &mut Vec<u8>,
relocs: &mut RelocSink, relocs: &mut RelocSink,
traps: &mut TrapSink, traps: &mut TrapSink,
) -> CodegenResult<(CodeOffset, CodeOffset)> { ) -> CodegenResult<CodeInfo> {
let total_size = self.compile(isa)?; let info = self.compile(isa)?;
let old_len = mem.len(); let old_len = mem.len();
mem.resize(old_len + total_size as usize, 0); mem.resize(old_len + info.total_size as usize, 0);
let code_size = let new_info =
unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) }; unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
Ok((code_size, total_size - code_size)) debug_assert!(new_info == info);
Ok(info)
} }
/// Compile the function. /// Compile the function.
@@ -115,8 +116,8 @@ impl Context {
/// represented by `isa`. This does not include the final step of emitting machine code into a /// represented by `isa`. This does not include the final step of emitting machine code into a
/// code sink. /// code sink.
/// ///
/// Returns the size of the function's code and read-only data. /// Returns information about the function's code and read-only data.
pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult<CodeOffset> { pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
let _tt = timing::compile(); let _tt = timing::compile();
self.verify_if(isa)?; self.verify_if(isa)?;
@@ -160,18 +161,18 @@ impl Context {
/// This function is unsafe since it does not perform bounds checking on the memory buffer, /// This function is unsafe since it does not perform bounds checking on the memory buffer,
/// and it can't guarantee that the `mem` pointer is valid. /// and it can't guarantee that the `mem` pointer is valid.
/// ///
/// Returns the size of the function's code. /// Returns information about the emitted code and data.
pub unsafe fn emit_to_memory( pub unsafe fn emit_to_memory(
&self, &self,
isa: &TargetIsa, isa: &TargetIsa,
mem: *mut u8, mem: *mut u8,
relocs: &mut RelocSink, relocs: &mut RelocSink,
traps: &mut TrapSink, traps: &mut TrapSink,
) -> CodeOffset { ) -> CodeInfo {
let _tt = timing::binemit(); let _tt = timing::binemit();
let mut sink = MemoryCodeSink::new(mem, relocs, traps); let mut sink = MemoryCodeSink::new(mem, relocs, traps);
isa.emit_function_to_memory(&self.func, &mut sink); isa.emit_function_to_memory(&self.func, &mut sink);
sink.code_size as CodeOffset sink.info
} }
/// Run the verifier on the function. /// Run the verifier on the function.
@@ -325,12 +326,13 @@ impl Context {
Ok(()) Ok(())
} }
/// Run the branch relaxation pass and return the final code size. /// Run the branch relaxation pass and return information about the function's code and
pub fn relax_branches(&mut self, isa: &TargetIsa) -> CodegenResult<CodeOffset> { /// read-only data.
let code_size = relax_branches(&mut self.func, isa)?; pub fn relax_branches(&mut self, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
let info = relax_branches(&mut self.func, isa)?;
self.verify_if(isa)?; self.verify_if(isa)?;
self.verify_locations_if(isa)?; self.verify_locations_if(isa)?;
Ok(code_size) Ok(info)
} }
/// Builds ranges and location for specified value labels. /// Builds ranges and location for specified value labels.

View File

@@ -339,4 +339,5 @@ fn disp4<CS: CodeSink + ?Sized>(destination: Ebb, func: &Function, sink: &mut CS
fn jt_disp4<CS: CodeSink + ?Sized>(jt: JumpTable, func: &Function, sink: &mut CS) { fn jt_disp4<CS: CodeSink + ?Sized>(jt: JumpTable, func: &Function, sink: &mut CS) {
let delta = func.jt_offsets[jt].wrapping_sub(sink.offset() + 4); let delta = func.jt_offsets[jt].wrapping_sub(sink.offset() + 4);
sink.put4(delta); sink.put4(delta);
sink.reloc_jt(Reloc::X86PCRelRodata4, jt);
} }

View File

@@ -138,9 +138,9 @@ impl Backend for FaerieBackend {
name: &str, name: &str,
ctx: &cranelift_codegen::Context, ctx: &cranelift_codegen::Context,
namespace: &ModuleNamespace<Self>, namespace: &ModuleNamespace<Self>,
code_size: u32, total_size: u32,
) -> ModuleResult<FaerieCompiledFunction> { ) -> ModuleResult<FaerieCompiledFunction> {
let mut code: Vec<u8> = vec![0; code_size as usize]; let mut code: Vec<u8> = vec![0; total_size as usize];
// Non-lexical lifetimes would obviate the braces here. // Non-lexical lifetimes would obviate the braces here.
{ {
@@ -153,7 +153,7 @@ impl Backend for FaerieBackend {
}; };
if let Some(ref mut trap_manifest) = self.trap_manifest { if let Some(ref mut trap_manifest) = self.trap_manifest {
let mut trap_sink = FaerieTrapSink::new(name, code_size); let mut trap_sink = FaerieTrapSink::new(name, total_size);
unsafe { unsafe {
ctx.emit_to_memory( ctx.emit_to_memory(
&*self.isa, &*self.isa,

View File

@@ -1424,8 +1424,8 @@ function %I64_JT(i64 [%rdi]) {
ebb0(v0: i64 [%rdi]): ebb0(v0: i64 [%rdi]):
; Note: The next two lines will need to change whenever instructions are ; Note: The next two lines will need to change whenever instructions are
; added or removed from this test. ; added or removed from this test.
[-, %rax] v1 = jump_table_base.i64 jt0 ; bin: 48 8d 05 00000039 [-, %rax] v1 = jump_table_base.i64 jt0 ; bin: 48 8d 05 00000039 PCRelRodata4(jt0)
[-, %r10] v2 = jump_table_base.i64 jt0 ; bin: 4c 8d 15 00000032 [-, %r10] v2 = jump_table_base.i64 jt0 ; bin: 4c 8d 15 00000032 PCRelRodata4(jt0)
[-, %rbx] v10 = iconst.i64 1 [-, %rbx] v10 = iconst.i64 1
[-, %r13] v11 = iconst.i64 2 [-, %r13] v11 = iconst.i64 2

View File

@@ -5,8 +5,7 @@
use crate::match_directive::match_directive; use crate::match_directive::match_directive;
use crate::subtest::{Context, SubTest, SubtestResult}; use crate::subtest::{Context, SubTest, SubtestResult};
use cranelift_codegen::binemit; use cranelift_codegen::binemit::{self, CodeInfo, CodeSink, RegDiversions};
use cranelift_codegen::binemit::{CodeSink, RegDiversions};
use cranelift_codegen::dbg::DisplayList; use cranelift_codegen::dbg::DisplayList;
use cranelift_codegen::ir; use cranelift_codegen::ir;
use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::ir::entities::AnyEntity;
@@ -96,9 +95,12 @@ impl binemit::CodeSink for TextSink {
write!(self.text, "{} ", code).unwrap(); write!(self.text, "{} ", code).unwrap();
} }
fn begin_rodata(&mut self) { fn begin_jumptables(&mut self) {
self.code_size = self.offset self.code_size = self.offset
} }
fn begin_rodata(&mut self) {}
fn end_codegen(&mut self) {}
} }
impl SubTest for TestBinEmit { impl SubTest for TestBinEmit {
@@ -164,7 +166,7 @@ impl SubTest for TestBinEmit {
} }
// Relax branches and compute EBB offsets based on the encodings. // Relax branches and compute EBB offsets based on the encodings.
let code_size = binemit::relax_branches(&mut func, isa) let CodeInfo { total_size, .. } = binemit::relax_branches(&mut func, isa)
.map_err(|e| pretty_error(&func, context.isa, e))?; .map_err(|e| pretty_error(&func, context.isa, e))?;
// Collect all of the 'bin:' directives on instructions. // Collect all of the 'bin:' directives on instructions.
@@ -288,7 +290,7 @@ impl SubTest for TestBinEmit {
} }
} }
sink.begin_rodata(); sink.begin_jumptables();
for (jt, jt_data) in func.jump_tables.iter() { for (jt, jt_data) in func.jump_tables.iter() {
let jt_offset = func.jt_offsets[jt]; let jt_offset = func.jt_offsets[jt];
@@ -298,10 +300,15 @@ impl SubTest for TestBinEmit {
} }
} }
if sink.offset != code_size { sink.begin_rodata();
// TODO: Read-only (constant pool) data.
sink.end_codegen();
if sink.offset != total_size {
return Err(format!( return Err(format!(
"Expected code size {}, got {}", "Expected code size {}, got {}",
code_size, sink.offset total_size, sink.offset
)); ));
} }

View File

@@ -4,8 +4,9 @@
use crate::subtest::{run_filecheck, Context, SubTest, SubtestResult}; use crate::subtest::{run_filecheck, Context, SubTest, SubtestResult};
use cranelift_codegen; use cranelift_codegen;
use cranelift_codegen::binemit::{self, CodeInfo};
use cranelift_codegen::ir;
use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::print_errors::pretty_error;
use cranelift_codegen::{binemit, ir};
use cranelift_reader::TestCommand; use cranelift_reader::TestCommand;
use log::info; use log::info;
use std::borrow::Cow; use std::borrow::Cow;
@@ -38,13 +39,13 @@ impl SubTest for TestCompile {
let isa = context.isa.expect("compile needs an ISA"); let isa = context.isa.expect("compile needs an ISA");
let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned()); let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
let code_size = comp_ctx let CodeInfo { total_size, .. } = comp_ctx
.compile(isa) .compile(isa)
.map_err(|e| pretty_error(&comp_ctx.func, context.isa, e))?; .map_err(|e| pretty_error(&comp_ctx.func, context.isa, e))?;
info!( info!(
"Generated {} bytes of code:\n{}", "Generated {} bytes of code:\n{}",
code_size, total_size,
comp_ctx.func.display(isa) comp_ctx.func.display(isa)
); );
@@ -56,10 +57,10 @@ impl SubTest for TestCompile {
&mut sink, &mut sink,
); );
if sink.offset != code_size { if sink.offset != total_size {
return Err(format!( return Err(format!(
"Expected code size {}, got {}", "Expected code size {}, got {}",
code_size, sink.offset total_size, sink.offset
)); ));
} }
@@ -105,5 +106,7 @@ impl binemit::CodeSink for SizeSink {
} }
fn reloc_jt(&mut self, _reloc: binemit::Reloc, _jt: ir::JumpTable) {} fn reloc_jt(&mut self, _reloc: binemit::Reloc, _jt: ir::JumpTable) {}
fn trap(&mut self, _code: ir::TrapCode, _srcloc: ir::SourceLoc) {} fn trap(&mut self, _code: ir::TrapCode, _srcloc: ir::SourceLoc) {}
fn begin_jumptables(&mut self) {}
fn begin_rodata(&mut self) {} fn begin_rodata(&mut self) {}
fn end_codegen(&mut self) {}
} }

View File

@@ -8,8 +8,9 @@
use super::HashMap; use super::HashMap;
use crate::data_context::DataContext; use crate::data_context::DataContext;
use crate::Backend; use crate::Backend;
use cranelift_codegen::binemit::{self, CodeInfo};
use cranelift_codegen::entity::{entity_impl, PrimaryMap}; use cranelift_codegen::entity::{entity_impl, PrimaryMap};
use cranelift_codegen::{binemit, ir, isa, CodegenError, Context}; use cranelift_codegen::{ir, isa, CodegenError, Context};
use failure::Fail; use failure::Fail;
use log::info; use log::info;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@@ -519,7 +520,7 @@ where
/// Define a function, producing the function body from the given `Context`. /// Define a function, producing the function body from the given `Context`.
/// ///
/// Returns the size of the function's code. /// Returns the size of the function's code and constant data.
/// ///
/// Note: After calling this function the given `Context` will contain the compiled function. /// Note: After calling this function the given `Context` will contain the compiled function.
pub fn define_function( pub fn define_function(
@@ -527,7 +528,7 @@ where
func: FuncId, func: FuncId,
ctx: &mut Context, ctx: &mut Context,
) -> ModuleResult<binemit::CodeOffset> { ) -> ModuleResult<binemit::CodeOffset> {
let code_size = ctx.compile(self.backend.isa()).map_err(|e| { let CodeInfo { total_size, .. } = ctx.compile(self.backend.isa()).map_err(|e| {
info!( info!(
"defining function {}: {}", "defining function {}: {}",
func, func,
@@ -550,12 +551,12 @@ where
&ModuleNamespace::<B> { &ModuleNamespace::<B> {
contents: &self.contents, contents: &self.contents,
}, },
code_size, total_size,
)?); )?);
self.contents.functions[func].compiled = compiled; self.contents.functions[func].compiled = compiled;
self.functions_to_finalize.push(func); self.functions_to_finalize.push(func);
Ok(code_size) Ok(total_size)
} }
/// Define a function, producing the data contents from the given `DataContext`. /// Define a function, producing the data contents from the given `DataContext`.

View File

@@ -65,7 +65,7 @@ fn handle_module(
let mut mem = vec![]; let mut mem = vec![];
// Compile and encode the result to machine code. // Compile and encode the result to machine code.
let (code_size, rodata_size) = context let code_info = context
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps) .compile_and_emit(isa, &mut mem, &mut relocs, &mut traps)
.map_err(|err| pretty_error(&context.func, Some(isa), err))?; .map_err(|err| pretty_error(&context.func, Some(isa), err))?;
@@ -74,7 +74,14 @@ fn handle_module(
} }
if flag_disasm { if flag_disasm {
print_all(isa, &mem, code_size, rodata_size, &relocs, &traps)?; print_all(
isa,
&mem,
code_info.code_size,
code_info.jumptables_size + code_info.rodata_size,
&relocs,
&traps,
)?;
} }
} }

View File

@@ -176,16 +176,16 @@ fn handle_module(
return Err(pretty_verifier_error(&context.func, fisa.isa, None, errors)); return Err(pretty_verifier_error(&context.func, fisa.isa, None, errors));
} }
} else { } else {
let (code_size, rodata_size) = context let code_info = context
.compile_and_emit(isa, &mut mem, &mut relocs, &mut traps) .compile_and_emit(isa, &mut mem, &mut relocs, &mut traps)
.map_err(|err| pretty_error(&context.func, fisa.isa, err))?; .map_err(|err| pretty_error(&context.func, fisa.isa, err))?;
if flag_print_size { if flag_print_size {
println!( println!(
"Function #{} code size: {} bytes", "Function #{} code size: {} bytes",
func_index, code_size + rodata_size func_index, code_info.total_size,
); );
total_module_code_size += code_size + rodata_size; total_module_code_size += code_info.total_size;
println!( println!(
"Function #{} bytecode size: {} bytes", "Function #{} bytecode size: {} bytes",
func_index, func_index,
@@ -194,7 +194,7 @@ fn handle_module(
} }
if flag_print_disasm { if flag_print_disasm {
saved_sizes = Some((code_size, rodata_size)); saved_sizes = Some((code_info.code_size, code_info.jumptables_size + code_info.rodata_size));
} }
} }