experimental: support for debug info (#118)

Signed-off-by: wpt967 <matt.aw@parity.io>
Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
Cyrill Leutwiler
2024-11-22 08:56:09 +01:00
committed by GitHub
parent 87f2bcefb3
commit dbb47fd13e
44 changed files with 730 additions and 285 deletions
+60 -37
View File
@@ -13,41 +13,52 @@ use self::ir_type::IRType;
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct DebugConfig {
/// The directory to dump the IRs to.
pub output_directory: PathBuf,
pub output_directory: Option<PathBuf>,
/// Whether debug info should be emitted.
pub emit_debug_info: bool,
}
impl DebugConfig {
/// A shortcut constructor.
pub fn new(output_directory: PathBuf) -> Self {
Self { output_directory }
pub const fn new(output_directory: Option<PathBuf>, emit_debug_info: bool) -> Self {
Self {
output_directory,
emit_debug_info,
}
}
/// Dumps the Yul IR.
pub fn dump_yul(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
}
Ok(())
}
/// Dumps the EVM legacy assembly IR.
pub fn dump_evmla(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
}
Ok(())
}
/// Dumps the Ethereal IR.
pub fn dump_ethir(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
}
Ok(())
}
@@ -58,12 +69,15 @@ impl DebugConfig {
contract_path: &str,
module: &inkwell::module::Module,
) -> anyhow::Result<()> {
let llvm_code = module.print_to_string().to_string();
if let Some(output_directory) = self.output_directory.as_ref() {
let llvm_code = module.print_to_string().to_string();
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, Some("unoptimized"), IRType::LLVM);
file_path.push(full_file_name);
std::fs::write(file_path, llvm_code)?;
let mut file_path = output_directory.to_owned();
let full_file_name =
Self::full_file_name(contract_path, Some("unoptimized"), IRType::LLVM);
file_path.push(full_file_name);
std::fs::write(file_path, llvm_code)?;
}
Ok(())
}
@@ -74,32 +88,39 @@ impl DebugConfig {
contract_path: &str,
module: &inkwell::module::Module,
) -> anyhow::Result<()> {
let llvm_code = module.print_to_string().to_string();
if let Some(output_directory) = self.output_directory.as_ref() {
let llvm_code = module.print_to_string().to_string();
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, Some("optimized"), IRType::LLVM);
file_path.push(full_file_name);
std::fs::write(file_path, llvm_code)?;
let mut file_path = output_directory.to_owned();
let full_file_name =
Self::full_file_name(contract_path, Some("optimized"), IRType::LLVM);
file_path.push(full_file_name);
std::fs::write(file_path, llvm_code)?;
}
Ok(())
}
/// Dumps the assembly.
pub fn dump_assembly(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Assembly);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Assembly);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
}
Ok(())
}
/// Dumps the code object.
pub fn dump_object(&self, contract_path: &str, code: &[u8]) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::SO);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::SO);
file_path.push(full_file_name);
std::fs::write(file_path, code)?;
}
Ok(())
}
@@ -112,10 +133,12 @@ impl DebugConfig {
contract_suffix: Option<&str>,
stage_json: &Vec<u8>,
) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, contract_suffix, IRType::JSON);
file_path.push(full_file_name);
std::fs::write(file_path, stage_json)?;
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, contract_suffix, IRType::JSON);
file_path.push(full_file_name);
std::fs::write(file_path, stage_json)?;
}
Ok(())
}
+1
View File
@@ -16,6 +16,7 @@ pub use self::polkavm::context::argument::Argument as PolkaVMArgument;
pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute;
pub use self::polkavm::context::build::Build as PolkaVMBuild;
pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType;
pub use self::polkavm::context::debug_info::DebugInfo;
pub use self::polkavm::context::evmla_data::EVMLAData as PolkaVMContextEVMLAData;
pub use self::polkavm::context::function::block::evmla_data::key::Key as PolkaVMFunctionBlockKey;
pub use self::polkavm::context::function::block::evmla_data::EVMLAData as PolkaVMFunctionBlockEVMLAData;
@@ -9,7 +9,7 @@ use itertools::Itertools;
use self::size_level::SizeLevel;
/// The LLVM optimizer settings.
/// The LLVM optimizer and code-gen settings.
#[derive(Debug, Serialize, Deserialize, Clone, Eq)]
pub struct Settings {
/// The middle-end optimization level.
@@ -1,7 +1,43 @@
//! The LLVM debug information.
use std::cell::RefCell;
use inkwell::debug_info::AsDIScope;
use num::Zero;
use inkwell::debug_info::DIScope;
/// Debug info scope stack
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScopeStack<'ctx> {
stack: Vec<DIScope<'ctx>>,
}
// Abstract the type of the DIScope stack.
impl<'ctx> ScopeStack<'ctx> {
pub fn from(item: DIScope<'ctx>) -> Self {
Self { stack: vec![item] }
}
/// Return the top of the scope stack, or None if the stack is empty.
pub fn top(&self) -> Option<DIScope<'ctx>> {
self.stack.last().copied()
}
/// Push a scope onto the stack.
pub fn push(&mut self, scope: DIScope<'ctx>) {
self.stack.push(scope)
}
/// Pop the scope at the top of the stack and return it.
/// Return None if the stack is empty.
pub fn pop(&mut self) -> Option<DIScope<'ctx>> {
self.stack.pop()
}
/// Return the number of scopes on the stack.
pub fn len(&self) -> usize {
self.stack.len()
}
}
/// The LLVM debug information.
pub struct DebugInfo<'ctx> {
@@ -9,6 +45,8 @@ pub struct DebugInfo<'ctx> {
compile_unit: inkwell::debug_info::DICompileUnit<'ctx>,
/// The debug info builder.
builder: inkwell::debug_info::DebugInfoBuilder<'ctx>,
/// Enclosing debug info scopes.
scope_stack: RefCell<ScopeStack<'ctx>>,
}
impl<'ctx> DebugInfo<'ctx> {
@@ -35,19 +73,43 @@ impl<'ctx> DebugInfo<'ctx> {
Self {
compile_unit,
builder,
scope_stack: RefCell::new(ScopeStack::from(compile_unit.as_debug_info_scope())),
}
}
/// Prepare an LLVM-IR module for debug-info generation
pub fn initialize_module(
&self,
llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>,
) {
let debug_metadata_value = llvm
.i32_type()
.const_int(inkwell::debug_info::debug_metadata_version() as u64, false);
module.add_basic_value_flag(
"Debug Info Version",
inkwell::module::FlagBehavior::Warning,
debug_metadata_value,
);
self.push_scope(self.compilation_unit().get_file().as_debug_info_scope());
}
/// Finalize debug-info for an LLVM-IR module.
pub fn finalize_module(&self) {
self.builder().finalize()
}
/// Creates a function info.
pub fn create_function(
&self,
name: &str,
) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> {
let flags = inkwell::debug_info::DIFlagsConstants::ZERO;
let subroutine_type = self.builder.create_subroutine_type(
self.compile_unit.get_file(),
Some(self.create_type(revive_common::BIT_LENGTH_FIELD)?),
Some(self.create_word_type(Some(flags))?.as_type()),
&[],
inkwell::debug_info::DIFlags::zero(),
flags,
);
let function = self.builder.create_function(
@@ -60,7 +122,7 @@ impl<'ctx> DebugInfo<'ctx> {
true,
false,
1,
inkwell::debug_info::DIFlags::zero(),
flags,
false,
);
@@ -74,24 +136,55 @@ impl<'ctx> DebugInfo<'ctx> {
Ok(function)
}
/// Creates a primitive type info.
pub fn create_type(
/// Creates primitive integer type debug-info.
pub fn create_primitive_type(
&self,
bit_length: usize,
) -> anyhow::Result<inkwell::debug_info::DIType<'ctx>> {
flags: Option<inkwell::debug_info::DIFlags>,
) -> anyhow::Result<inkwell::debug_info::DIBasicType<'ctx>> {
let di_flags = flags.unwrap_or(inkwell::debug_info::DIFlagsConstants::ZERO);
let di_encoding: u32 = 0;
let type_name = String::from("U") + bit_length.to_string().as_str();
self.builder
.create_basic_type(
"U256",
bit_length as u64,
0,
inkwell::debug_info::DIFlags::zero(),
)
.map(|basic_type| basic_type.as_type())
.create_basic_type(type_name.as_str(), bit_length as u64, di_encoding, di_flags)
.map_err(|error| anyhow::anyhow!("Debug info error: {}", error))
}
/// Finalizes the builder.
pub fn finalize(&self) {
self.builder.finalize();
/// Returns the debug-info model of word-sized integer types.
pub fn create_word_type(
&self,
flags: Option<inkwell::debug_info::DIFlags>,
) -> anyhow::Result<inkwell::debug_info::DIBasicType<'ctx>> {
self.create_primitive_type(revive_common::BIT_LENGTH_WORD, flags)
}
/// Return the DIBuilder.
pub fn builder(&self) -> &inkwell::debug_info::DebugInfoBuilder<'ctx> {
&self.builder
}
/// Return the compilation unit. {
pub fn compilation_unit(&self) -> &inkwell::debug_info::DICompileUnit<'ctx> {
&self.compile_unit
}
/// Push a debug-info scope onto the stack.
pub fn push_scope(&self, scope: DIScope<'ctx>) {
self.scope_stack.borrow_mut().push(scope)
}
/// Pop the top of the debug-info scope stack and return it.
pub fn pop_scope(&self) -> Option<DIScope<'ctx>> {
self.scope_stack.borrow_mut().pop()
}
/// Return the top of the debug-info scope stack.
pub fn top_scope(&self) -> Option<DIScope<'ctx>> {
self.scope_stack.borrow().top()
}
/// Return the number of debug-info scopes on the scope stack.
pub fn num_scopes(&self) -> usize {
self.scope_stack.borrow().len()
}
}
@@ -17,4 +17,8 @@ impl<'ctx> Declaration<'ctx> {
) -> Self {
Self { r#type, value }
}
pub fn function_value(&self) -> inkwell::values::FunctionValue<'ctx> {
self.value
}
}
@@ -11,6 +11,8 @@ pub mod yul_data;
use std::collections::HashMap;
use inkwell::debug_info::AsDIScope;
use crate::optimizer::settings::size_level::SizeLevel;
use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
@@ -94,6 +96,14 @@ impl<'ctx> Function<'ctx> {
self.declaration
}
/// Returns the debug-info scope.
pub fn get_debug_scope(&self) -> Option<inkwell::debug_info::DIScope<'ctx>> {
self.declaration()
.function_value()
.get_subprogram()
.map(|scp| scp.as_debug_info_scope())
}
/// Returns the N-th parameter of the function.
pub fn get_nth_param(&self, index: usize) -> inkwell::values::BasicValueEnum<'ctx> {
self.declaration()
@@ -54,12 +54,14 @@ where
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
context.set_current_function(runtime::FUNCTION_DEPLOY_CODE)?;
context.set_current_function(runtime::FUNCTION_DEPLOY_CODE, None)?;
context.set_basic_block(context.current_function().borrow().entry_block());
context.set_code_type(CodeType::Deploy);
self.inner.into_llvm(context)?;
context.set_debug_location(0, 0, None)?;
match context
.basic_block()
.get_last_instruction()
@@ -72,8 +74,11 @@ where
}
context.set_basic_block(context.current_function().borrow().return_block());
context.set_debug_location(0, 0, None)?;
context.build_return(None);
context.pop_debug_scope();
Ok(())
}
}
@@ -125,6 +125,8 @@ impl Entry {
where
D: Dependency + Clone,
{
context.set_debug_location(0, 0, None)?;
let is_deploy = context
.current_function()
.borrow()
@@ -214,7 +216,7 @@ where
true,
);
context.set_current_function(runtime::FUNCTION_ENTRY)?;
context.set_current_function(runtime::FUNCTION_ENTRY, None)?;
context.set_basic_block(context.current_function().borrow().entry_block());
Self::initialize_globals(context)?;
@@ -225,6 +227,8 @@ where
context.set_basic_block(context.current_function().borrow().return_block());
context.build_unreachable();
context.pop_debug_scope();
Ok(())
}
}
@@ -34,7 +34,7 @@ where
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
context.set_current_function(runtime::FUNCTION_LOAD_IMMUTABLE_DATA)?;
context.set_current_function(runtime::FUNCTION_LOAD_IMMUTABLE_DATA, None)?;
context.set_basic_block(context.current_function().borrow().entry_block());
let immutable_data_size_pointer = context
@@ -111,6 +111,8 @@ where
context.set_basic_block(return_block);
context.build_return(None);
context.pop_debug_scope();
Ok(())
}
}
@@ -54,11 +54,14 @@ where
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
context.set_current_function(runtime::FUNCTION_RUNTIME_CODE)?;
context.set_current_function(runtime::FUNCTION_RUNTIME_CODE, None)?;
context.set_basic_block(context.current_function().borrow().entry_block());
context.set_code_type(CodeType::Runtime);
self.inner.into_llvm(context)?;
context.set_debug_location(0, 0, None)?;
match context
.basic_block()
.get_last_instruction()
@@ -73,6 +76,8 @@ where
context.set_basic_block(context.current_function().borrow().return_block());
context.build_unreachable();
context.pop_debug_scope();
Ok(())
}
}
+131 -20
View File
@@ -5,7 +5,7 @@ pub mod argument;
pub mod attribute;
pub mod build;
pub mod code_type;
// pub mod debug_info;
pub mod debug_info;
pub mod evmla_data;
pub mod function;
pub mod global;
@@ -21,6 +21,8 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use inkwell::debug_info::AsDIScope;
use inkwell::debug_info::DIScope;
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
@@ -35,7 +37,7 @@ use self::address_space::AddressSpace;
use self::attribute::Attribute;
use self::build::Build;
use self::code_type::CodeType;
// use self::debug_info::DebugInfo;
use self::debug_info::DebugInfo;
use self::evmla_data::EVMLAData;
use self::function::declaration::Declaration as FunctionDeclaration;
use self::function::intrinsics::Intrinsics;
@@ -85,9 +87,9 @@ where
/// Whether to append the metadata hash at the end of bytecode.
include_metadata_hash: bool,
/// The debug info of the current module.
// debug_info: DebugInfo<'ctx>,
debug_info: Option<DebugInfo<'ctx>>,
/// The debug configuration telling whether to dump the needed IRs.
debug_config: Option<DebugConfig>,
debug_config: DebugConfig,
/// The Solidity data.
solidity_data: Option<SolidityData>,
@@ -207,7 +209,7 @@ where
optimizer: Optimizer,
dependency_manager: Option<D>,
include_metadata_hash: bool,
debug_config: Option<DebugConfig>,
debug_config: DebugConfig,
) -> Self {
Self::link_stdlib_module(llvm, &module);
Self::link_polkavm_imports(llvm, &module);
@@ -216,6 +218,11 @@ where
let intrinsics = Intrinsics::new(llvm, &module);
let llvm_runtime = LLVMRuntime::new(llvm, &module, &optimizer);
let debug_info = debug_config.emit_debug_info.then(|| {
let debug_info = DebugInfo::new(&module);
debug_info.initialize_module(llvm, &module);
debug_info
});
Self {
llvm,
@@ -232,7 +239,8 @@ where
dependency_manager,
include_metadata_hash,
// debug_info,
debug_info,
debug_config,
solidity_data: None,
@@ -255,9 +263,9 @@ where
let target_machine = TargetMachine::new(Target::PVM, self.optimizer.settings())?;
target_machine.set_target_data(self.module());
if let Some(ref debug_config) = self.debug_config {
debug_config.dump_llvm_ir_unoptimized(contract_path, self.module())?;
}
self.debug_config
.dump_llvm_ir_unoptimized(contract_path, self.module())?;
self.verify().map_err(|error| {
anyhow::anyhow!(
"The contract `{}` unoptimized LLVM IR verification error: {}",
@@ -275,9 +283,10 @@ where
error
)
})?;
if let Some(ref debug_config) = self.debug_config {
debug_config.dump_llvm_ir_optimized(contract_path, self.module())?;
}
self.debug_config
.dump_llvm_ir_optimized(contract_path, self.module())?;
self.verify().map_err(|error| {
anyhow::anyhow!(
"The contract `{}` optimized LLVM IR verification error: {}",
@@ -298,11 +307,11 @@ where
let shared_object = revive_linker::link(buffer.as_slice())?;
if let Some(ref debug_config) = self.debug_config {
debug_config.dump_object(contract_path, &shared_object)?;
}
self.debug_config
.dump_object(contract_path, &shared_object)?;
let polkavm_bytecode = revive_linker::polkavm_linker(shared_object)?;
let polkavm_bytecode =
revive_linker::polkavm_linker(shared_object, !self.debug_config().emit_debug_info)?;
let build = match crate::polkavm::build_assembly_text(
contract_path,
@@ -428,6 +437,21 @@ where
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
let value = self.module().add_function(name, r#type, linkage);
if self.debug_info().is_some() {
self.builder().unset_current_debug_location();
let func_scope = match value.get_subprogram() {
None => {
let fn_name = value.get_name().to_str()?;
let scp = self.build_function_debug_info(fn_name, 0)?;
value.set_subprogram(scp);
scp
}
Some(scp) => scp,
};
self.push_debug_scope(func_scope.as_debug_info_scope());
self.set_debug_location(0, 0, Some(func_scope.as_debug_info_scope()))?;
}
let entry_block = self.llvm.append_basic_block(value, "entry");
let return_block = self.llvm.append_basic_block(value, "return");
@@ -461,6 +485,8 @@ where
let function = Rc::new(RefCell::new(function));
self.functions.insert(name.to_string(), function.clone());
self.pop_debug_scope();
Ok(function)
}
@@ -476,15 +502,95 @@ where
.expect("Must be declared before use")
}
/// Sets the current active function.
pub fn set_current_function(&mut self, name: &str) -> anyhow::Result<()> {
/// Sets the current active function. If debug-info generation is enabled,
/// constructs a debug-scope and pushes in on the scope-stack.
pub fn set_current_function(&mut self, name: &str, line: Option<u32>) -> anyhow::Result<()> {
let function = self.functions.get(name).cloned().ok_or_else(|| {
anyhow::anyhow!("Failed to activate an undeclared function `{}`", name)
})?;
self.current_function = Some(function);
if let Some(scope) = self.current_function().borrow().get_debug_scope() {
self.push_debug_scope(scope);
}
self.set_debug_location(line.unwrap_or_default(), 0, None)?;
Ok(())
}
/// Builds a debug-info scope for a function.
pub fn build_function_debug_info(
&self,
name: &str,
line_no: u32,
) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> {
let Some(debug_info) = self.debug_info() else {
anyhow::bail!("expected debug-info builders");
};
let builder = debug_info.builder();
let file = debug_info.compilation_unit().get_file();
let scope = file.as_debug_info_scope();
let flags = inkwell::debug_info::DIFlagsConstants::PUBLIC;
let return_type = debug_info.create_word_type(Some(flags))?.as_type();
let subroutine_type = builder.create_subroutine_type(file, Some(return_type), &[], flags);
Ok(builder.create_function(
scope,
name,
None,
file,
line_no,
subroutine_type,
false,
true,
1,
flags,
false,
))
}
/// Set the debug info location.
///
/// No-op if the emitting debug info is disabled.
///
/// If `scope` is `None` the top scope will be used.
pub fn set_debug_location(
&self,
line: u32,
column: u32,
scope: Option<DIScope<'ctx>>,
) -> anyhow::Result<()> {
let Some(debug_info) = self.debug_info() else {
return Ok(());
};
let scope = match scope {
Some(scp) => scp,
None => debug_info.top_scope().expect("expected a debug-info scope"),
};
let location =
debug_info
.builder()
.create_debug_location(self.llvm(), line, column, scope, None);
self.builder().set_current_debug_location(location);
Ok(())
}
/// Pushes a debug-info scope to the stack.
pub fn push_debug_scope(&self, scope: DIScope<'ctx>) {
if let Some(debug_info) = self.debug_info() {
debug_info.push_scope(scope);
}
}
/// Pops the top of the debug-info scope stack.
pub fn pop_debug_scope(&self) {
if let Some(debug_info) = self.debug_info() {
debug_info.pop_scope();
}
}
/// Pushes a new loop context to the stack.
pub fn push_loop(
&mut self,
@@ -554,9 +660,14 @@ where
.expect("The dependency manager is unset")
}
/// Returns the debug info.
pub fn debug_info(&self) -> Option<&DebugInfo<'ctx>> {
self.debug_info.as_ref()
}
/// Returns the debug config reference.
pub fn debug_config(&self) -> Option<&DebugConfig> {
self.debug_config.as_ref()
pub fn debug_config(&self) -> &DebugConfig {
&self.debug_config
}
/// Appends a new basic block to the current function.
@@ -15,7 +15,7 @@ pub fn create_context(
let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings);
Context::<DummyDependency>::new(llvm, module, optimizer, None, true, None)
Context::<DummyDependency>::new(llvm, module, optimizer, None, true, Default::default())
}
#[test]
+4 -6
View File
@@ -29,7 +29,7 @@ pub fn build_assembly_text(
contract_path: &str,
bytecode: &[u8],
metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]>,
debug_config: Option<&DebugConfig>,
debug_config: &DebugConfig,
) -> anyhow::Result<Build> {
let program_blob = ProgramBlob::parse(bytecode.into())
.map_err(anyhow::Error::msg)
@@ -49,9 +49,7 @@ pub fn build_assembly_text(
format!("Failed to convert disassembled code to string for contract: {contract_path}")
})?;
if let Some(debug_config) = debug_config {
debug_config.dump_assembly(contract_path, &assembly_text)?;
}
debug_config.dump_assembly(contract_path, &assembly_text)?;
Ok(Build::new(
assembly_text.to_owned(),
@@ -98,7 +96,7 @@ pub trait Dependency {
path: &str,
optimizer_settings: OptimizerSettings,
include_metadata_hash: bool,
debug_config: Option<DebugConfig>,
debug_config: DebugConfig,
) -> anyhow::Result<String>;
/// Resolves a full contract path.
@@ -118,7 +116,7 @@ impl Dependency for DummyDependency {
_path: &str,
_optimizer_settings: OptimizerSettings,
_include_metadata_hash: bool,
_debug_config: Option<DebugConfig>,
_debug_config: DebugConfig,
) -> anyhow::Result<String> {
Ok(String::new())
}