mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-22 04:27:58 +00:00
Prevent frontend function confusion (#383)
Function symbols can clash as we compile multiple YUL `object` definition into the same `LLVM` module. - Disambiguate via unique function symbols based its location (runtime or deploy code). - Use `LinkOnceODR` linkage for compiler builtin helpers. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"Baseline": 960,
|
||||
"Computation": 2356,
|
||||
"DivisionArithmetics": 8964,
|
||||
"ERC20": 17143,
|
||||
"Events": 1680,
|
||||
"FibonacciIterative": 1502,
|
||||
"Flipper": 2137,
|
||||
"SHA1": 7740
|
||||
"Baseline": 932,
|
||||
"Computation": 2313,
|
||||
"DivisionArithmetics": 8959,
|
||||
"ERC20": 16993,
|
||||
"Events": 1692,
|
||||
"FibonacciIterative": 1474,
|
||||
"Flipper": 2098,
|
||||
"SHA1": 7751
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
//! The deploy code function.
|
||||
|
||||
use crate::polkavm::context::code_type::CodeType;
|
||||
use crate::polkavm::context::function::runtime;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::WriteLLVM;
|
||||
@@ -38,16 +37,16 @@ where
|
||||
0,
|
||||
Some(inkwell::module::Linkage::Private),
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
|
||||
self.inner.declare(context)
|
||||
}
|
||||
|
||||
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
||||
context.set_current_function(runtime::FUNCTION_DEPLOY_CODE, None)?;
|
||||
context.set_current_function(runtime::FUNCTION_DEPLOY_CODE, None, false)?;
|
||||
|
||||
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)?;
|
||||
|
||||
@@ -138,6 +138,7 @@ impl WriteLLVM for Entry {
|
||||
0,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
|
||||
context.declare_global(
|
||||
@@ -160,7 +161,7 @@ impl WriteLLVM for Entry {
|
||||
/// The `entry` function loads calldata, sets globals and calls the runtime or deploy code.
|
||||
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
||||
let entry = context
|
||||
.get_function(runtime::FUNCTION_ENTRY)
|
||||
.get_function(runtime::FUNCTION_ENTRY, false)
|
||||
.expect("the entry function should already be declared")
|
||||
.borrow()
|
||||
.declaration;
|
||||
@@ -171,7 +172,7 @@ impl WriteLLVM for Entry {
|
||||
true,
|
||||
);
|
||||
|
||||
context.set_current_function(runtime::FUNCTION_ENTRY, None)?;
|
||||
context.set_current_function(runtime::FUNCTION_ENTRY, None, false)?;
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
Self::initialize_globals(context)?;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! The runtime code function.
|
||||
|
||||
use crate::polkavm::context::code_type::CodeType;
|
||||
use crate::polkavm::context::function::runtime;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::WriteLLVM;
|
||||
@@ -38,16 +37,16 @@ where
|
||||
0,
|
||||
Some(inkwell::module::Linkage::Private),
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
|
||||
self.inner.declare(context)
|
||||
}
|
||||
|
||||
fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> {
|
||||
context.set_current_function(runtime::FUNCTION_RUNTIME_CODE, None)?;
|
||||
context.set_current_function(runtime::FUNCTION_RUNTIME_CODE, None, false)?;
|
||||
|
||||
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)?;
|
||||
|
||||
@@ -426,8 +426,15 @@ impl<'ctx> Context<'ctx> {
|
||||
return_values_length: usize,
|
||||
linkage: Option<inkwell::module::Linkage>,
|
||||
location: Option<(u32, u32)>,
|
||||
is_frontend: bool,
|
||||
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
|
||||
let value = self.module().add_function(name, r#type, linkage);
|
||||
assert!(
|
||||
self.get_function(name, is_frontend).is_none(),
|
||||
"ICE: function '{name}' declared subsequentally"
|
||||
);
|
||||
|
||||
let name = self.internal_function_name(name, is_frontend);
|
||||
let value = self.module().add_function(&name, r#type, linkage);
|
||||
|
||||
if self.debug_info().is_some() {
|
||||
self.builder().unset_current_debug_location();
|
||||
@@ -468,7 +475,7 @@ impl<'ctx> Context<'ctx> {
|
||||
};
|
||||
|
||||
let function = Function::new(
|
||||
name.to_owned(),
|
||||
name.clone(),
|
||||
FunctionDeclaration::new(r#type, value),
|
||||
r#return,
|
||||
entry_block,
|
||||
@@ -476,7 +483,7 @@ impl<'ctx> Context<'ctx> {
|
||||
);
|
||||
Function::set_default_attributes(self.llvm, function.declaration(), &self.optimizer);
|
||||
let function = Rc::new(RefCell::new(function));
|
||||
self.functions.insert(name.to_string(), function.clone());
|
||||
self.functions.insert(name, function.clone());
|
||||
|
||||
self.pop_debug_scope();
|
||||
|
||||
@@ -484,8 +491,14 @@ impl<'ctx> Context<'ctx> {
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the specified function.
|
||||
pub fn get_function(&self, name: &str) -> Option<Rc<RefCell<Function<'ctx>>>> {
|
||||
self.functions.get(name).cloned()
|
||||
pub fn get_function(
|
||||
&self,
|
||||
name: &str,
|
||||
is_frontend: bool,
|
||||
) -> Option<Rc<RefCell<Function<'ctx>>>> {
|
||||
self.functions
|
||||
.get(&self.internal_function_name(name, is_frontend))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the current active function.
|
||||
@@ -501,8 +514,9 @@ impl<'ctx> Context<'ctx> {
|
||||
&mut self,
|
||||
name: &str,
|
||||
location: Option<(u32, u32)>,
|
||||
frontend: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let function = self.functions.get(name).cloned().ok_or_else(|| {
|
||||
let function = self.get_function(name, frontend).ok_or_else(|| {
|
||||
anyhow::anyhow!("Failed to activate an undeclared function `{}`", name)
|
||||
})?;
|
||||
self.current_function = Some(function);
|
||||
@@ -1371,4 +1385,13 @@ impl<'ctx> Context<'ctx> {
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the internal function name.
|
||||
fn internal_function_name(&self, name: &str, is_frontend: bool) -> String {
|
||||
if is_frontend {
|
||||
format!("{name}_{}", self.code_type().unwrap())
|
||||
} else {
|
||||
name.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ pub trait RuntimeFunction {
|
||||
Self::NAME,
|
||||
Self::r#type(context),
|
||||
0,
|
||||
Some(inkwell::module::Linkage::External), // TODO: `Private` emits unrelocated AUIPC?
|
||||
Some(inkwell::module::Linkage::LinkOnceODR),
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
|
||||
let mut attributes = Self::ATTRIBUTES.to_vec();
|
||||
@@ -45,6 +46,12 @@ pub trait RuntimeFunction {
|
||||
&attributes,
|
||||
true,
|
||||
);
|
||||
let function = function.borrow().declaration().function_value();
|
||||
let comdat = context
|
||||
.module()
|
||||
.get_or_insert_comdat(&format!("{}_comdat", Self::NAME));
|
||||
comdat.set_selection_kind(inkwell::comdat::ComdatSelectionKind::NoDuplicates);
|
||||
function.as_global_value().set_comdat(comdat);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -52,7 +59,7 @@ pub trait RuntimeFunction {
|
||||
/// Get the function declaration.
|
||||
fn declaration<'ctx>(context: &Context<'ctx>) -> Declaration<'ctx> {
|
||||
context
|
||||
.get_function(Self::NAME)
|
||||
.get_function(Self::NAME, false)
|
||||
.unwrap_or_else(|| panic!("runtime function {} should be declared", Self::NAME))
|
||||
.borrow()
|
||||
.declaration()
|
||||
@@ -60,7 +67,7 @@ pub trait RuntimeFunction {
|
||||
|
||||
/// Emit the function.
|
||||
fn emit(&self, context: &mut Context) -> anyhow::Result<()> {
|
||||
context.set_current_function(Self::NAME, None)?;
|
||||
context.set_current_function(Self::NAME, None, false)?;
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
let return_value = self.emit_body(context)?;
|
||||
@@ -99,7 +106,7 @@ pub trait RuntimeFunction {
|
||||
) -> inkwell::values::BasicValueEnum<'ctx> {
|
||||
let name = Self::NAME;
|
||||
context
|
||||
.get_function(name)
|
||||
.get_function(name, false)
|
||||
.unwrap_or_else(|| panic!("runtime function {name} should be declared"))
|
||||
.borrow()
|
||||
.declaration()
|
||||
|
||||
@@ -38,6 +38,7 @@ pub fn check_attribute_null_pointer_is_invalid() {
|
||||
1,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.expect("Failed to add function");
|
||||
assert!(!function
|
||||
@@ -62,6 +63,7 @@ pub fn check_attribute_optimize_for_size_mode_3() {
|
||||
1,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.expect("Failed to add function");
|
||||
assert!(!function
|
||||
@@ -86,6 +88,7 @@ pub fn check_attribute_optimize_for_size_mode_z() {
|
||||
1,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.expect("Failed to add function");
|
||||
assert!(function
|
||||
@@ -110,6 +113,7 @@ pub fn check_attribute_min_size_mode_3() {
|
||||
1,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.expect("Failed to add function");
|
||||
assert!(!function
|
||||
@@ -134,6 +138,7 @@ pub fn check_attribute_min_size_mode_z() {
|
||||
1,
|
||||
Some(inkwell::module::Linkage::External),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.expect("Failed to add function");
|
||||
assert!(function
|
||||
|
||||
@@ -210,7 +210,7 @@ pub fn load<'ctx>(
|
||||
let name = <Load as RuntimeFunction>::NAME;
|
||||
context.build_call(
|
||||
context
|
||||
.get_function(name)
|
||||
.get_function(name, false)
|
||||
.expect("is always declared for runtime code")
|
||||
.borrow()
|
||||
.declaration(),
|
||||
|
||||
@@ -159,6 +159,7 @@ impl PolkaVMWriteLLVM for Block {
|
||||
context.set_current_function(
|
||||
current_function.as_str(),
|
||||
Some((self.location.line, self.location.column)),
|
||||
false,
|
||||
)?;
|
||||
|
||||
if let Some(debug_info) = context.debug_info() {
|
||||
|
||||
@@ -135,7 +135,7 @@ impl FunctionCall {
|
||||
values.push(value);
|
||||
}
|
||||
values.reverse();
|
||||
let function = context.get_function(name.as_str()).ok_or_else(|| {
|
||||
let function = context.get_function(name.as_str(), true).ok_or_else(|| {
|
||||
anyhow::anyhow!("{} Undeclared function `{}`", location, name)
|
||||
})?;
|
||||
|
||||
|
||||
@@ -215,8 +215,9 @@ impl PolkaVMWriteLLVM for FunctionDefinition {
|
||||
self.identifier.as_str(),
|
||||
function_type,
|
||||
self.result.len(),
|
||||
Some(inkwell::module::Linkage::Private),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
Some((self.location.line, self.location.column)),
|
||||
true,
|
||||
)?;
|
||||
PolkaVMFunction::set_attributes(
|
||||
context.llvm(),
|
||||
@@ -235,6 +236,7 @@ impl PolkaVMWriteLLVM for FunctionDefinition {
|
||||
context.set_current_function(
|
||||
self.identifier.as_str(),
|
||||
Some((self.location.line, self.location.column)),
|
||||
true,
|
||||
)?;
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::collections::BTreeSet;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use inkwell::debug_info::AsDIScope;
|
||||
use revive_llvm_context::PolkaVMCodeType;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -184,6 +185,12 @@ impl Object {
|
||||
|
||||
impl PolkaVMWriteLLVM for Object {
|
||||
fn declare(&mut self, context: &mut PolkaVMContext) -> anyhow::Result<()> {
|
||||
if self.identifier.ends_with("_deployed") {
|
||||
context.set_code_type(PolkaVMCodeType::Runtime);
|
||||
} else {
|
||||
context.set_code_type(PolkaVMCodeType::Deploy);
|
||||
}
|
||||
|
||||
revive_llvm_context::PolkaVMLoadImmutableDataFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMStoreImmutableDataFunction.declare(context)?;
|
||||
|
||||
@@ -230,40 +237,12 @@ impl PolkaVMWriteLLVM for Object {
|
||||
.into_iter()
|
||||
{
|
||||
context
|
||||
.get_function(name)
|
||||
.get_function(name, false)
|
||||
.expect("Always exists")
|
||||
.borrow_mut()
|
||||
.set_yul_data(revive_llvm_context::PolkaVMFunctionYulData::default());
|
||||
}
|
||||
|
||||
entry.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMLoadImmutableDataFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreImmutableDataFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMLoadHeapWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<0>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<1>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<2>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMSignedRemainderFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -280,8 +259,37 @@ impl PolkaVMWriteLLVM for Object {
|
||||
|
||||
context.set_debug_location(self.location.line, self.location.column, None)?;
|
||||
if self.identifier.ends_with("_deployed") {
|
||||
context.set_code_type(PolkaVMCodeType::Runtime);
|
||||
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(self.code).into_llvm(context)?;
|
||||
} else {
|
||||
context.set_code_type(PolkaVMCodeType::Deploy);
|
||||
revive_llvm_context::PolkaVMEntryFunction::default().into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMLoadImmutableDataFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreImmutableDataFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMLoadHeapWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<0>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<1>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<2>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMSignedRemainderFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user