mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-15 06:51:07 +00:00
94ec34c4d5
Separate between compilation and linker phases to allow deploy time linking and back-porting era compiler changes to fix #91. Unlinked contract binaries (caused by missing libraries or missing factory dependencies in turn) are emitted as raw ELF object. Few drive by fixes: - #98 - A compiler panic on missing libraries definitions. - Fixes some incosistent type forwarding in JSON output (empty string vs. null object). - Remove the unused fallback for size optimization setting. - Remove the broken `--lvm-ir` mode. - CI workflow fixes. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Signed-off-by: xermicus <bigcyrill@hotmail.com> Signed-off-by: xermicus <cyrill@parity.io>
164 lines
5.5 KiB
Rust
164 lines
5.5 KiB
Rust
//! Translates a log or event call.
|
|
|
|
use inkwell::values::BasicValue;
|
|
use revive_common::BYTE_LENGTH_WORD;
|
|
|
|
use crate::polkavm::context::runtime::RuntimeFunction;
|
|
use crate::polkavm::context::Context;
|
|
use crate::polkavm::WriteLLVM;
|
|
|
|
/// A function for emitting EVM event logs from contract code.
|
|
pub struct EventLog<const N: usize>;
|
|
|
|
impl<const N: usize> RuntimeFunction for EventLog<N> {
|
|
const NAME: &'static str = match N {
|
|
0 => "__revive_log_0",
|
|
1 => "__revive_log_1",
|
|
2 => "__revive_log_2",
|
|
3 => "__revive_log_3",
|
|
4 => "__revive_log_4",
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> {
|
|
let mut parameter_types = vec![context.xlen_type().into(), context.xlen_type().into()];
|
|
parameter_types.extend_from_slice(&[context.word_type().into(); N]);
|
|
context.void_type().fn_type(¶meter_types, false)
|
|
}
|
|
|
|
fn emit_body<'ctx>(
|
|
&self,
|
|
context: &mut Context<'ctx>,
|
|
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
|
|
let input_offset = Self::paramater(context, 0).into_int_value();
|
|
let input_length = Self::paramater(context, 1).into_int_value();
|
|
let input_pointer = context.builder().build_ptr_to_int(
|
|
context.build_heap_gep(input_offset, input_length)?.value,
|
|
context.xlen_type(),
|
|
"event_input_offset",
|
|
)?;
|
|
|
|
let arguments = if N == 0 {
|
|
[
|
|
context.xlen_type().const_zero().as_basic_value_enum(),
|
|
context.xlen_type().const_zero().as_basic_value_enum(),
|
|
input_pointer.as_basic_value_enum(),
|
|
input_length.as_basic_value_enum(),
|
|
]
|
|
} else {
|
|
let topics_buffer_size = N * BYTE_LENGTH_WORD;
|
|
let topics_buffer_pointer = context.build_alloca_at_entry(
|
|
context.byte_type().array_type(topics_buffer_size as u32),
|
|
"topics_buffer",
|
|
);
|
|
|
|
for n in 0..N {
|
|
let topic = Self::paramater(context, n + 2);
|
|
let topic_buffer_offset = context
|
|
.xlen_type()
|
|
.const_int((n * BYTE_LENGTH_WORD) as u64, false);
|
|
context.build_store(
|
|
context.build_gep(
|
|
topics_buffer_pointer,
|
|
&[context.xlen_type().const_zero(), topic_buffer_offset],
|
|
context.byte_type(),
|
|
&format!("topic_buffer_{N}_gep"),
|
|
),
|
|
context.build_byte_swap(topic.as_basic_value_enum())?,
|
|
)?;
|
|
}
|
|
|
|
[
|
|
context
|
|
.builder()
|
|
.build_ptr_to_int(
|
|
topics_buffer_pointer.value,
|
|
context.xlen_type(),
|
|
"event_topics_offset",
|
|
)?
|
|
.as_basic_value_enum(),
|
|
context
|
|
.xlen_type()
|
|
.const_int(N as u64, false)
|
|
.as_basic_value_enum(),
|
|
input_pointer.as_basic_value_enum(),
|
|
input_length.as_basic_value_enum(),
|
|
]
|
|
};
|
|
|
|
context.build_runtime_call(
|
|
revive_runtime_api::polkavm_imports::DEPOSIT_EVENT,
|
|
&arguments,
|
|
);
|
|
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
impl WriteLLVM for EventLog<0> {
|
|
fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::declare(self, context)
|
|
}
|
|
|
|
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::emit(&self, context)
|
|
}
|
|
}
|
|
|
|
impl WriteLLVM for EventLog<1> {
|
|
fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::declare(self, context)
|
|
}
|
|
|
|
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::emit(&self, context)
|
|
}
|
|
}
|
|
|
|
impl WriteLLVM for EventLog<2> {
|
|
fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::declare(self, context)
|
|
}
|
|
|
|
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::emit(&self, context)
|
|
}
|
|
}
|
|
|
|
impl WriteLLVM for EventLog<3> {
|
|
fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::declare(self, context)
|
|
}
|
|
|
|
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::emit(&self, context)
|
|
}
|
|
}
|
|
|
|
impl WriteLLVM for EventLog<4> {
|
|
fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::declare(self, context)
|
|
}
|
|
|
|
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
|
<Self as RuntimeFunction>::emit(&self, context)
|
|
}
|
|
}
|
|
|
|
/// Translates a log or event call.
|
|
pub fn log<'ctx, const N: usize>(
|
|
context: &mut Context<'ctx>,
|
|
input_offset: inkwell::values::IntValue<'ctx>,
|
|
input_length: inkwell::values::IntValue<'ctx>,
|
|
topics: [inkwell::values::BasicValueEnum<'ctx>; N],
|
|
) -> anyhow::Result<()> {
|
|
let declaration = <EventLog<N> as RuntimeFunction>::declaration(context);
|
|
let mut arguments = vec![
|
|
context.safe_truncate_int_to_xlen(input_offset)?.into(),
|
|
context.safe_truncate_int_to_xlen(input_length)?.into(),
|
|
];
|
|
arguments.extend_from_slice(&topics);
|
|
context.build_call(declaration, &arguments, "log");
|
|
Ok(())
|
|
}
|