Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

llvm-context: remove the linear memory pointer indirection #211

Merged
merged 2 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ This is a development pre-release.

Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`

### Fixed
- A bug causing incorrect loads from the emulated EVM linear memory.
- A missing integer truncate after switching to 64bit.

## v0.1.0-dev.10

This is a development pre-release.
Expand Down
40 changes: 40 additions & 0 deletions crates/integration/contracts/MLoad.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.28;

/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "MLoad"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "e2179b8e"
}
}
]
}
*/

contract MLoad {
constructor() payable {
assert(g() == 0);
}

function g() public payable returns (uint m) {
assembly {
m := mload(0)
}
}
}
1 change: 1 addition & 0 deletions crates/integration/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ test_spec!(create2, "CreateB", "Create2.sol");
test_spec!(transfer, "Transfer", "Transfer.sol");
test_spec!(send, "Send", "Send.sol");
test_spec!(function_pointer, "FunctionPointer", "FunctionPointer.sol");
test_spec!(mload, "MLoad", "MLoad.sol");

fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate {
Expand Down
6 changes: 0 additions & 6 deletions crates/llvm-context/src/polkavm/const/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,9 @@ pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4);
/// The pointer width sized type.
pub static XLEN: usize = revive_common::BIT_LENGTH_X32;

/// The heap memory pointer pointer global variable name.
pub static GLOBAL_HEAP_MEMORY_POINTER: &str = "memory_pointer";

/// The calldata size global variable name.
pub static GLOBAL_CALLDATA_SIZE: &str = "calldatasize";

/// The call flags global variable name.
pub static GLOBAL_CALL_FLAGS: &str = "call_flags";

/// The deployer call header size that consists of:
/// - bytecode hash (32 bytes)
pub const DEPLOYER_CALL_HEADER_SIZE: usize = revive_common::BYTE_LENGTH_WORD;
35 changes: 5 additions & 30 deletions crates/llvm-context/src/polkavm/context/function/runtime/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,13 @@ impl Entry {
where
D: Dependency + Clone,
{
context.set_global(
crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER,
context.llvm().ptr_type(AddressSpace::Heap.into()),
AddressSpace::Stack,
context.xlen_type().get_undef(),
);
context.build_store(
context
.get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)?
.into(),
context.build_sbrk(
context.xlen_type().const_zero(),
context.xlen_type().const_zero(),
)?,
)?;

context.set_global(
crate::polkavm::GLOBAL_CALLDATA_SIZE,
context.xlen_type(),
AddressSpace::Stack,
context.xlen_type().get_undef(),
);

context.set_global(
crate::polkavm::GLOBAL_CALL_FLAGS,
context.word_type(),
AddressSpace::Stack,
context.word_const(0),
);

Ok(())
}

Expand All @@ -70,6 +47,11 @@ impl Entry {
.build_runtime_call(revive_runtime_api::polkavm_imports::CALL_DATA_SIZE, &[])
.expect("the call_data_size syscall method should return a value")
.into_int_value();
let call_data_size_value = context.builder().build_int_truncate(
call_data_size_value,
context.xlen_type(),
"call_data_size_truncated",
)?;
context
.builder()
.build_store(call_data_size_pointer, call_data_size_value)?;
Expand All @@ -90,13 +72,6 @@ impl Entry {
.borrow()
.get_nth_param(Self::ARGUMENT_INDEX_CALL_FLAGS);

context.set_global(
crate::polkavm::GLOBAL_CALL_FLAGS,
is_deploy.get_type(),
AddressSpace::Stack,
is_deploy.into_int_value(),
);

let deploy_code_call_block = context.append_basic_block("deploy_code_call_block");
let runtime_code_call_block = context.append_basic_block("runtime_code_call_block");

Expand Down
27 changes: 14 additions & 13 deletions crates/llvm-context/src/polkavm/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,17 +1209,17 @@ where

/// Build a call to PolkaVM `msize` for querying the linear memory size.
pub fn build_msize(&self) -> anyhow::Result<inkwell::values::IntValue<'ctx>> {
Ok(self
.builder()
.build_call(
self.runtime_api_method(revive_runtime_api::polkavm_imports::MEMORY_SIZE),
&[],
"call_msize",
)?
.try_as_basic_value()
.left()
.expect("sbrk returns an int")
.into_int_value())
let memory_size_pointer = self
.module()
.get_global(revive_runtime_api::polkavm_imports::MEMORY_SIZE)
.expect("the memory size symbol should have been declared")
.as_pointer_value();
let memory_size_value = self.builder().build_load(
self.xlen_type(),
memory_size_pointer,
"memory_size_value",
)?;
Ok(memory_size_value.into_int_value())
}

/// Call PolkaVM `sbrk` for extending the heap by `offset` + `size`,
Expand Down Expand Up @@ -1265,8 +1265,9 @@ where
self.build_heap_alloc(offset, length)?;

let heap_start = self
.get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)?
.value
.module()
.get_global(revive_runtime_api::polkavm_imports::MEMORY)
.expect("the memory symbol should have been declared")
.as_pointer_value();
Ok(self.build_gep(
Pointer::new(self.byte_type(), AddressSpace::Stack, heap_start),
Expand Down
10 changes: 3 additions & 7 deletions crates/runtime-api/src/polkavm_imports.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
#define EVM_WORD_SIZE 32
#define ALIGN(size) ((size + EVM_WORD_SIZE - 1) & ~(EVM_WORD_SIZE - 1))
#define MAX_MEMORY_SIZE (64 * 1024)
static char __memory[MAX_MEMORY_SIZE];
static uint32_t __memory_size = 0;
char __memory[MAX_MEMORY_SIZE];
uint32_t __memory_size = 0;

void * __sbrk_internal(uint32_t offset, uint32_t size) {
void * __sbrk_internal(uint32_t offset, uint32_t size) {
if (offset >= MAX_MEMORY_SIZE || size > MAX_MEMORY_SIZE) {
return NULL;
}
Expand All @@ -27,10 +27,6 @@ void * __sbrk_internal(uint32_t offset, uint32_t size) {
return (void *)&__memory[__memory_size];
}

uint32_t __msize() {
return __memory_size;
}

void * memset(void *b, int c, size_t len) {
uint8_t *dest = b;
while (len-- > 0) *dest++ = c;
Expand Down
19 changes: 7 additions & 12 deletions crates/runtime-api/src/polkavm_imports.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//! This crate vendors the [PolkaVM][0] C API and provides a LLVM module for interacting
//! with the `pallet-revive` runtime API.
//! At present, the revive pallet requires blobs to export `call` and `deploy`,
//! and offers a bunch of [runtime API methods][1]. The provided [module] implements
//! those exports and imports.
//! [0]: [https://crates.io/crates/polkavm]
//! [1]: [https://docs.rs/pallet-contracts/26.0.0/pallet_contracts/api_doc/index.html]

use inkwell::{context::Context, memory_buffer::MemoryBuffer, module::Module, support::LLVMString};

include!(concat!(env!("OUT_DIR"), "/polkavm_imports.rs"));

pub static SBRK: &str = "__sbrk_internal";
/// The emulated EVM heap memory global symbol.
pub static MEMORY: &str = "__memory";

pub static MEMORY_SIZE: &str = "__msize";
/// The emulated EVM heap memory size global symbol.
pub static MEMORY_SIZE: &str = "__memory_size";

pub static SBRK: &str = "__sbrk_internal";

pub static ADDRESS: &str = "address";

Expand Down Expand Up @@ -82,9 +78,8 @@ pub static WEIGHT_TO_FEE: &str = "weight_to_fee";

/// All imported runtime API symbols.
/// Useful for configuring common attributes and linkage.
pub static IMPORTS: [&str; 35] = [
pub static IMPORTS: [&str; 34] = [
SBRK,
MEMORY_SIZE,
ADDRESS,
BALANCE,
BALANCE_OF,
Expand Down
Loading