mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 16:51:04 +00:00
Contract calls (#19)
This commit is contained in:
Generated
+25
-25
@@ -47,9 +47,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-rlp"
|
name = "alloy-rlp"
|
||||||
version = "0.3.4"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac"
|
checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -68,7 +68,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
"syn-solidity",
|
"syn-solidity",
|
||||||
"tiny-keccak",
|
"tiny-keccak",
|
||||||
]
|
]
|
||||||
@@ -284,7 +284,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -473,7 +473,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -500,9 +500,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-hex"
|
name = "const-hex"
|
||||||
version = "1.11.4"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6"
|
checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@@ -1047,7 +1047,7 @@ source = "git+https://github.com/TheDan64/inkwell.git?rev=6c0fb56b3554e939f9ca61
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1519,9 +1519,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.83"
|
version = "1.0.84"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
|
checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -2013,22 +2013,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.202"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.202"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2200,9 +2200,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.65"
|
version = "2.0.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
|
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2218,7 +2218,7 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2265,7 +2265,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2416,7 +2416,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2438,7 +2438,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -2677,14 +2677,14 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.7.0"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zeroize_derive",
|
"zeroize_derive",
|
||||||
]
|
]
|
||||||
@@ -2697,7 +2697,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.65",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
|
contract Call {
|
||||||
|
function value_transfer(address payable destination) public payable {
|
||||||
|
destination.transfer(msg.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function echo(bytes memory payload) public pure returns (bytes memory) {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function call(
|
||||||
|
address callee,
|
||||||
|
bytes memory payload
|
||||||
|
) public pure returns (bytes memory) {
|
||||||
|
return Call(callee).echo(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,6 +135,19 @@ sol!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sol!(
|
||||||
|
contract Call {
|
||||||
|
function value_transfer(address payable destination) public payable;
|
||||||
|
|
||||||
|
function echo(bytes memory payload) public payable returns (bytes memory);
|
||||||
|
|
||||||
|
function call(
|
||||||
|
address callee,
|
||||||
|
bytes memory payload
|
||||||
|
) public payable returns (bytes memory);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
impl Contract {
|
impl Contract {
|
||||||
/// Execute the contract.
|
/// Execute the contract.
|
||||||
///
|
///
|
||||||
@@ -441,6 +454,42 @@ impl Contract {
|
|||||||
calldata: MCopy::memcpyCall::new((payload,)).abi_encode(),
|
calldata: MCopy::memcpyCall::new((payload,)).abi_encode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call_value_transfer(destination: Address) -> Self {
|
||||||
|
let code = include_str!("../contracts/Call.sol");
|
||||||
|
let name = "Call";
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||||
|
pvm_runtime: crate::compile_blob(name, code),
|
||||||
|
calldata: Call::value_transferCall::new((destination,)).abi_encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_call(callee: Address, payload: Vec<u8>) -> Self {
|
||||||
|
let code = include_str!("../contracts/Call.sol");
|
||||||
|
let name = "Call";
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||||
|
pvm_runtime: crate::compile_blob(name, code),
|
||||||
|
calldata: Call::callCall::new((callee, payload)).abi_encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_constructor() -> Self {
|
||||||
|
let code = include_str!("../contracts/Call.sol");
|
||||||
|
let name = "Call";
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||||
|
pvm_runtime: crate::compile_blob(name, code),
|
||||||
|
calldata: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ struct Frame {
|
|||||||
output: CallOutput,
|
output: CallOutput,
|
||||||
/// The export to call.
|
/// The export to call.
|
||||||
export: Export,
|
export: Export,
|
||||||
|
/// The returndata from the last contract call.
|
||||||
|
returndata: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Frame {
|
impl Default for Frame {
|
||||||
@@ -93,6 +95,7 @@ impl Default for Frame {
|
|||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
export: Default::default(),
|
export: Default::default(),
|
||||||
|
returndata: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,8 +227,8 @@ impl TransactionBuilder {
|
|||||||
.unwrap_or_else(|| panic!("contract code not found: {blob_hash}"));
|
.unwrap_or_else(|| panic!("contract code not found: {blob_hash}"));
|
||||||
let (mut instance, _) = prepare(code, None);
|
let (mut instance, _) = prepare(code, None);
|
||||||
let export = match self.context.top_frame().export {
|
let export = match self.context.top_frame().export {
|
||||||
Export::Call => runtime_api::CALL,
|
Export::Call => runtime_api::exports::CALL,
|
||||||
Export::Deploy(_) => runtime_api::DEPLOY,
|
Export::Deploy(_) => runtime_api::exports::DEPLOY,
|
||||||
};
|
};
|
||||||
let export = instance.module().lookup_export(export).unwrap();
|
let export = instance.module().lookup_export(export).unwrap();
|
||||||
self.call_on(&mut instance, export)
|
self.call_on(&mut instance, export)
|
||||||
@@ -354,7 +357,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::INPUT,
|
runtime_api::imports::INPUT,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
|
||||||
let (mut caller, transaction) = caller.split();
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -371,7 +374,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::RETURN,
|
runtime_api::imports::RETURN,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
data_ptr: u32,
|
data_ptr: u32,
|
||||||
@@ -390,7 +393,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::VALUE_TRANSFERRED,
|
runtime_api::imports::VALUE_TRANSFERRED,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
|
||||||
let (mut caller, transaction) = caller.split();
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -426,7 +429,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::SET_STORAGE,
|
runtime_api::imports::SET_STORAGE,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
key_ptr: u32,
|
key_ptr: u32,
|
||||||
key_len: u32,
|
key_len: u32,
|
||||||
@@ -461,7 +464,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::GET_STORAGE,
|
runtime_api::imports::GET_STORAGE,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
key_ptr: u32,
|
key_ptr: u32,
|
||||||
key_len: u32,
|
key_len: u32,
|
||||||
@@ -495,7 +498,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::HASH_KECCAK_256,
|
runtime_api::imports::HASH_KECCAK_256,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
input_ptr: u32,
|
input_ptr: u32,
|
||||||
input_len: u32,
|
input_len: u32,
|
||||||
@@ -516,7 +519,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::NOW,
|
runtime_api::imports::NOW,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
||||||
let (mut caller, _) = caller.split();
|
let (mut caller, _) = caller.split();
|
||||||
|
|
||||||
@@ -537,7 +540,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::BLOCK_NUMBER,
|
runtime_api::imports::BLOCK_NUMBER,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
||||||
let (mut caller, _) = caller.split();
|
let (mut caller, _) = caller.split();
|
||||||
|
|
||||||
@@ -558,7 +561,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::ADDRESS,
|
runtime_api::imports::ADDRESS,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
||||||
let (mut caller, transaction) = caller.split();
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -580,7 +583,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::CALLER,
|
runtime_api::imports::CALLER,
|
||||||
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
|
||||||
let (mut caller, transaction) = caller.split();
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -602,7 +605,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::DEPOSIT_EVENT,
|
runtime_api::imports::DEPOSIT_EVENT,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
topics_ptr: u32,
|
topics_ptr: u32,
|
||||||
topics_len: u32,
|
topics_len: u32,
|
||||||
@@ -639,7 +642,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::INSTANTIATE,
|
runtime_api::imports::INSTANTIATE,
|
||||||
|caller: Caller<Transaction>, argument_ptr: u32| {
|
|caller: Caller<Transaction>, argument_ptr: u32| {
|
||||||
let (mut caller, transaction) = caller.split();
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -732,7 +735,122 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
linker
|
linker
|
||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::CODE_SIZE,
|
runtime_api::imports::CALL,
|
||||||
|
|caller: Caller<Transaction>, argument_ptr: u32| -> Result<u32, Trap> {
|
||||||
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
struct Arguments {
|
||||||
|
_flags: u32,
|
||||||
|
address_ptr: u32,
|
||||||
|
_ref_time_limit: u64,
|
||||||
|
proof_size_limit: u64,
|
||||||
|
deposit_ptr: u32,
|
||||||
|
value_ptr: u32,
|
||||||
|
input_data_ptr: u32,
|
||||||
|
input_data_len: u32,
|
||||||
|
output_ptr: u32,
|
||||||
|
output_len_ptr: u32,
|
||||||
|
}
|
||||||
|
let mut buffer = [0; std::mem::size_of::<Arguments>()];
|
||||||
|
caller.read_memory_into_slice(argument_ptr, &mut buffer)?;
|
||||||
|
let arguments: Arguments = unsafe { std::mem::transmute(buffer) };
|
||||||
|
|
||||||
|
assert_eq!({ arguments.proof_size_limit }, 0);
|
||||||
|
assert_eq!({ arguments.deposit_ptr }, u32::MAX);
|
||||||
|
|
||||||
|
let amount = if arguments.value_ptr != u32::MAX {
|
||||||
|
let value = caller.read_memory_into_vec(arguments.value_ptr, 32)?;
|
||||||
|
U256::from_le_slice(&value)
|
||||||
|
} else {
|
||||||
|
U256::ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
match transaction.top_account_mut().value.checked_sub(amount) {
|
||||||
|
Some(deducted) => transaction.top_account_mut().value = deducted,
|
||||||
|
None => {
|
||||||
|
log::info!("call failed: insufficient balance {amount}");
|
||||||
|
return Ok(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = caller.read_memory_into_vec(arguments.address_ptr, 32)?;
|
||||||
|
let word = U256::from_le_slice(&bytes);
|
||||||
|
let address = Address::from_word(word.into());
|
||||||
|
log::info!("call {address}");
|
||||||
|
|
||||||
|
if !transaction.state.accounts.contains_key(&address) {
|
||||||
|
log::info!(
|
||||||
|
"balance transfer {amount} from {} to {address}",
|
||||||
|
transaction.top_frame().callee
|
||||||
|
);
|
||||||
|
|
||||||
|
transaction
|
||||||
|
.state
|
||||||
|
.accounts
|
||||||
|
.entry(address)
|
||||||
|
.or_insert_with(|| Account {
|
||||||
|
value: amount,
|
||||||
|
contract: None,
|
||||||
|
storage: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if transaction.stack.len() >= Transaction::CALL_STACK_SIZE {
|
||||||
|
log::info!("deployment faild: maximum stack depth reached");
|
||||||
|
return Ok(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let calldata = caller
|
||||||
|
.read_memory_into_vec(arguments.input_data_ptr, arguments.input_data_len)?;
|
||||||
|
|
||||||
|
let (state, output) = transaction
|
||||||
|
.state
|
||||||
|
.clone()
|
||||||
|
.transaction()
|
||||||
|
.callee(address)
|
||||||
|
.callvalue(amount)
|
||||||
|
.calldata(calldata)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
let bytes_to_copy = caller.read_u32(arguments.output_len_ptr)? as usize;
|
||||||
|
let output_size = output.data.len();
|
||||||
|
assert!(
|
||||||
|
bytes_to_copy <= output_size,
|
||||||
|
"output buffer of {bytes_to_copy}b too small for {output_size}b"
|
||||||
|
);
|
||||||
|
|
||||||
|
transaction.top_frame_mut().returndata = output.data.to_vec();
|
||||||
|
caller.write_memory(
|
||||||
|
arguments.output_ptr,
|
||||||
|
&transaction.top_frame().returndata[..bytes_to_copy],
|
||||||
|
)?;
|
||||||
|
caller.write_memory(arguments.output_len_ptr, &output.data.len().to_le_bytes())?;
|
||||||
|
assert_eq!(
|
||||||
|
transaction.top_frame().returndata.len(),
|
||||||
|
caller.read_u32(arguments.output_len_ptr)? as usize
|
||||||
|
);
|
||||||
|
|
||||||
|
let success = if output.flags == ReturnFlags::Success {
|
||||||
|
log::info!("call succeeded");
|
||||||
|
transaction.state = state;
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
log::info!("call failed: callee reverted {:?}", output.flags);
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(success)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
linker
|
||||||
|
.func_wrap(
|
||||||
|
runtime_api::imports::CODE_SIZE,
|
||||||
|caller: Caller<Transaction>, address_ptr: u32| {
|
|caller: Caller<Transaction>, address_ptr: u32| {
|
||||||
let (caller, transaction) = caller.split();
|
let (caller, transaction) = caller.split();
|
||||||
|
|
||||||
@@ -754,6 +872,36 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
linker
|
||||||
|
.func_wrap(
|
||||||
|
runtime_api::imports::RETURNDATACOPY,
|
||||||
|
|caller: Caller<Transaction>,
|
||||||
|
destination_ptr: u32,
|
||||||
|
offset: u32,
|
||||||
|
size: u32|
|
||||||
|
-> Result<(), Trap> {
|
||||||
|
let (mut caller, transaction) = caller.split();
|
||||||
|
|
||||||
|
let offset = offset as usize;
|
||||||
|
let slice_end = offset
|
||||||
|
.checked_add(size as usize)
|
||||||
|
.expect("offset + size overflows");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
slice_end <= transaction.top_frame().returndata.len(),
|
||||||
|
"offset + size is larger than RETURNDATASIZE"
|
||||||
|
);
|
||||||
|
|
||||||
|
caller.write_memory(
|
||||||
|
destination_ptr,
|
||||||
|
&transaction.top_frame().returndata[offset..slice_end],
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
linker
|
linker
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,7 +920,7 @@ pub fn instantiate_module(
|
|||||||
module: &Module,
|
module: &Module,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
) -> (Instance<Transaction>, ExportIndex) {
|
) -> (Instance<Transaction>, ExportIndex) {
|
||||||
let export = module.lookup_export(runtime_api::CALL).unwrap();
|
let export = module.lookup_export(runtime_api::imports::CALL).unwrap();
|
||||||
let func = link_host_functions(engine).instantiate_pre(module).unwrap();
|
let func = link_host_functions(engine).instantiate_pre(module).unwrap();
|
||||||
let instance = func.instantiate().unwrap();
|
let instance = func.instantiate().unwrap();
|
||||||
|
|
||||||
@@ -789,7 +937,7 @@ pub fn prepare(code: &[u8], config: Option<Config>) -> (Instance<Transaction>, E
|
|||||||
module_config.set_gas_metering(Some(GasMeteringKind::Sync));
|
module_config.set_gas_metering(Some(GasMeteringKind::Sync));
|
||||||
|
|
||||||
let module = Module::from_blob(&engine, &module_config, blob).unwrap();
|
let module = Module::from_blob(&engine, &module_config, blob).unwrap();
|
||||||
let export = module.lookup_export(runtime_api::CALL).unwrap();
|
let export = module.lookup_export(runtime_api::exports::CALL).unwrap();
|
||||||
let func = link_host_functions(&engine)
|
let func = link_host_functions(&engine)
|
||||||
.instantiate_pre(&module)
|
.instantiate_pre(&module)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -523,6 +523,36 @@ fn ext_code_size() {
|
|||||||
assert_eq!(received, expected);
|
assert_eq!(received, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_transfer() {
|
||||||
|
// Succeeds in remix (shanghai) but traps the interpreter
|
||||||
|
let (state, _) = assert_success(&Contract::call_value_transfer(Default::default()), false);
|
||||||
|
|
||||||
|
assert_eq!(state.accounts().len(), 2);
|
||||||
|
assert!(state.accounts().get(&Address::default()).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn echo() {
|
||||||
|
let (state, address) = State::new_deployed(Contract::call_constructor());
|
||||||
|
|
||||||
|
let expected = vec![1, 2, 3, 4, 5];
|
||||||
|
let contract = Contract::call_call(address, expected.clone());
|
||||||
|
let (_, output) = state
|
||||||
|
.transaction()
|
||||||
|
.with_default_account(&contract.pvm_runtime)
|
||||||
|
.calldata(contract.calldata)
|
||||||
|
.call();
|
||||||
|
|
||||||
|
assert_eq!(output.flags, ReturnFlags::Success);
|
||||||
|
|
||||||
|
let received = alloy_primitives::Bytes::abi_decode(&output.data, true)
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
assert_eq!(expected, received);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mcopy() {
|
fn mcopy() {
|
||||||
let expected = vec![1, 2, 3];
|
let expected = vec![1, 2, 3];
|
||||||
@@ -532,5 +562,6 @@ fn mcopy() {
|
|||||||
let received = alloy_primitives::Bytes::abi_decode(&output.data, true)
|
let received = alloy_primitives::Bytes::abi_decode(&output.data, true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
assert_eq!(expected, received);
|
assert_eq!(expected, received);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,68 @@
|
|||||||
//! Runtime API import and export symbols.
|
//! Runtime API import and export symbols.
|
||||||
|
|
||||||
/// The contract deploy export.
|
pub mod exports {
|
||||||
pub static CALL: &str = "call";
|
/// The contract deploy export.
|
||||||
|
pub static CALL: &str = "call";
|
||||||
|
|
||||||
/// The contract call export.
|
/// The contract call export.
|
||||||
pub static DEPLOY: &str = "deploy";
|
pub static DEPLOY: &str = "deploy";
|
||||||
|
|
||||||
/// All exported symbols.
|
/// All exported symbols.
|
||||||
/// Useful for configuring common attributes and linkage.
|
/// Useful for configuring common attributes and linkage.
|
||||||
pub static EXPORTS: [&str; 2] = [CALL, DEPLOY];
|
pub static EXPORTS: [&str; 2] = [CALL, DEPLOY];
|
||||||
|
}
|
||||||
|
|
||||||
pub static ADDRESS: &str = "address";
|
pub mod imports {
|
||||||
|
pub static ADDRESS: &str = "address";
|
||||||
|
|
||||||
pub static BLOCK_NUMBER: &str = "block_number";
|
pub static BLOCK_NUMBER: &str = "block_number";
|
||||||
|
|
||||||
pub static CALLER: &str = "caller";
|
pub static CALL: &str = "seal_call";
|
||||||
|
|
||||||
pub static CODE_SIZE: &str = "code_size";
|
pub static CALLER: &str = "caller";
|
||||||
|
|
||||||
pub static DEPOSIT_EVENT: &str = "deposit_event";
|
pub static CODE_SIZE: &str = "code_size";
|
||||||
|
|
||||||
pub static GET_STORAGE: &str = "get_storage";
|
pub static DEPOSIT_EVENT: &str = "deposit_event";
|
||||||
|
|
||||||
pub static HASH_KECCAK_256: &str = "hash_keccak_256";
|
pub static GET_STORAGE: &str = "get_storage";
|
||||||
|
|
||||||
pub static INPUT: &str = "input";
|
pub static HASH_KECCAK_256: &str = "hash_keccak_256";
|
||||||
|
|
||||||
pub static INSTANTIATE: &str = "instantiate";
|
pub static INPUT: &str = "input";
|
||||||
|
|
||||||
pub static NOW: &str = "now";
|
pub static INSTANTIATE: &str = "instantiate";
|
||||||
|
|
||||||
pub static RETURN: &str = "seal_return";
|
pub static NOW: &str = "now";
|
||||||
|
|
||||||
pub static SET_STORAGE: &str = "set_storage";
|
pub static RETURN: &str = "seal_return";
|
||||||
|
|
||||||
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
pub static RETURNDATACOPY: &str = "returndatacopy";
|
||||||
|
|
||||||
/// All imported runtime API symbols..
|
pub static SET_STORAGE: &str = "set_storage";
|
||||||
/// Useful for configuring common attributes and linkage.
|
|
||||||
pub static IMPORTS: [&str; 12] = [
|
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||||
ADDRESS,
|
|
||||||
BLOCK_NUMBER,
|
/// All imported runtime API symbols.
|
||||||
CALLER,
|
/// Useful for configuring common attributes and linkage.
|
||||||
DEPOSIT_EVENT,
|
pub static IMPORTS: [&str; 15] = [
|
||||||
GET_STORAGE,
|
ADDRESS,
|
||||||
HASH_KECCAK_256,
|
BLOCK_NUMBER,
|
||||||
INPUT,
|
CALL,
|
||||||
INSTANTIATE,
|
CALLER,
|
||||||
NOW,
|
CODE_SIZE,
|
||||||
RETURN,
|
DEPOSIT_EVENT,
|
||||||
SET_STORAGE,
|
GET_STORAGE,
|
||||||
VALUE_TRANSFERRED,
|
HASH_KECCAK_256,
|
||||||
];
|
INPUT,
|
||||||
|
INSTANTIATE,
|
||||||
|
NOW,
|
||||||
|
RETURN,
|
||||||
|
RETURNDATACOPY,
|
||||||
|
SET_STORAGE,
|
||||||
|
VALUE_TRANSFERRED,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/// PolkaVM __sbrk API symbol to extend the heap memory.
|
/// PolkaVM __sbrk API symbol to extend the heap memory.
|
||||||
pub static SBRK: &str = "__sbrk";
|
pub static SBRK: &str = "__sbrk";
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ use crate::polkavm::context::function::Function;
|
|||||||
/// The functions are automatically linked to the LLVM implementations if the signatures match.
|
/// The functions are automatically linked to the LLVM implementations if the signatures match.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LLVMRuntime<'ctx> {
|
pub struct LLVMRuntime<'ctx> {
|
||||||
/// The LLVM personality function, used for exception handling.
|
|
||||||
pub personality: FunctionDeclaration<'ctx>,
|
|
||||||
/// The LLVM exception throwing function.
|
|
||||||
pub cxa_throw: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
/// The corresponding LLVM runtime function.
|
||||||
pub shl: FunctionDeclaration<'ctx>,
|
pub shl: FunctionDeclaration<'ctx>,
|
||||||
/// The corresponding LLVM runtime function.
|
/// The corresponding LLVM runtime function.
|
||||||
@@ -37,29 +32,6 @@ pub struct LLVMRuntime<'ctx> {
|
|||||||
/// The corresponding LLVM runtime function.
|
/// The corresponding LLVM runtime function.
|
||||||
pub sha3: FunctionDeclaration<'ctx>,
|
pub sha3: FunctionDeclaration<'ctx>,
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub system_request: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
//pub far_call: FunctionDeclaration<'ctx>,
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub far_call_byref: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub static_call: FunctionDeclaration<'ctx>,
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub static_call_byref: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub delegate_call: FunctionDeclaration<'ctx>,
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub delegate_call_byref: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub mimic_call: FunctionDeclaration<'ctx>,
|
|
||||||
/// The corresponding LLVM runtime function.
|
|
||||||
pub mimic_call_byref: FunctionDeclaration<'ctx>,
|
|
||||||
|
|
||||||
/// The corresponding LLVM runtime function.
|
/// The corresponding LLVM runtime function.
|
||||||
pub r#return: FunctionDeclaration<'ctx>,
|
pub r#return: FunctionDeclaration<'ctx>,
|
||||||
/// The corresponding LLVM runtime function.
|
/// The corresponding LLVM runtime function.
|
||||||
@@ -139,30 +111,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
|||||||
module: &inkwell::module::Module<'ctx>,
|
module: &inkwell::module::Module<'ctx>,
|
||||||
optimizer: &Optimizer,
|
optimizer: &Optimizer,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let personality = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_PERSONALITY,
|
|
||||||
llvm.i32_type().fn_type(&[], false),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let cxa_throw = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_CXA_THROW,
|
|
||||||
llvm.void_type().fn_type(
|
|
||||||
vec![
|
|
||||||
llvm.ptr_type(AddressSpace::Stack.into())
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into();
|
|
||||||
3
|
|
||||||
]
|
|
||||||
.as_slice(),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_cxa_throw_attributes(llvm, cxa_throw);
|
|
||||||
|
|
||||||
let shl = Self::declare(
|
let shl = Self::declare(
|
||||||
module,
|
module,
|
||||||
Self::FUNCTION_SHL,
|
Self::FUNCTION_SHL,
|
||||||
@@ -288,138 +236,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let system_request = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_SYSTEM_REQUEST,
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.fn_type(
|
|
||||||
vec![
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
llvm.ptr_type(AddressSpace::Stack.into())
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
]
|
|
||||||
.as_slice(),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, system_request, optimizer);
|
|
||||||
|
|
||||||
let external_call_arguments: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into();
|
|
||||||
crate::polkavm::context::function::runtime::entry::Entry::MANDATORY_ARGUMENTS_COUNT
|
|
||||||
+ crate::polkavm::EXTRA_ABI_DATA_SIZE
|
|
||||||
];
|
|
||||||
let mut mimic_call_arguments = external_call_arguments.clone();
|
|
||||||
mimic_call_arguments.push(
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut external_call_arguments_by_ref: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![
|
|
||||||
llvm.ptr_type(AddressSpace::Generic.into())
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
];
|
|
||||||
external_call_arguments_by_ref.extend::<Vec<inkwell::types::BasicMetadataTypeEnum>>(vec![
|
|
||||||
llvm.custom_width_int_type(
|
|
||||||
revive_common::BIT_LENGTH_WORD as u32
|
|
||||||
)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into();
|
|
||||||
crate::polkavm::EXTRA_ABI_DATA_SIZE
|
|
||||||
]);
|
|
||||||
let mut mimic_call_arguments_by_ref = external_call_arguments_by_ref.clone();
|
|
||||||
mimic_call_arguments_by_ref.push(
|
|
||||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
|
||||||
.as_basic_type_enum()
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let external_call_result_type = llvm
|
|
||||||
.struct_type(
|
|
||||||
&[
|
|
||||||
llvm.ptr_type(AddressSpace::Generic.into())
|
|
||||||
.as_basic_type_enum(),
|
|
||||||
llvm.bool_type().as_basic_type_enum(),
|
|
||||||
],
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.as_basic_type_enum();
|
|
||||||
|
|
||||||
//let far_call = Self::declare(
|
|
||||||
// module,
|
|
||||||
// Self::FUNCTION_FARCALL,
|
|
||||||
// external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
|
||||||
// Some(inkwell::module::Linkage::External),
|
|
||||||
//);
|
|
||||||
//Function::set_default_attributes(llvm, far_call, optimizer);
|
|
||||||
let static_call = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_STATICCALL,
|
|
||||||
external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, static_call, optimizer);
|
|
||||||
let delegate_call = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_DELEGATECALL,
|
|
||||||
external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, delegate_call, optimizer);
|
|
||||||
let mimic_call = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_MIMICCALL,
|
|
||||||
external_call_result_type.fn_type(mimic_call_arguments.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, mimic_call, optimizer);
|
|
||||||
|
|
||||||
let far_call_byref = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_FARCALL_BYREF,
|
|
||||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, far_call_byref, optimizer);
|
|
||||||
let static_call_byref = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_STATICCALL_BYREF,
|
|
||||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, static_call_byref, optimizer);
|
|
||||||
let delegate_call_byref = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_DELEGATECALL_BYREF,
|
|
||||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, delegate_call_byref, optimizer);
|
|
||||||
let mimic_call_byref = Self::declare(
|
|
||||||
module,
|
|
||||||
Self::FUNCTION_MIMICCALL_BYREF,
|
|
||||||
external_call_result_type.fn_type(mimic_call_arguments_by_ref.as_slice(), false),
|
|
||||||
Some(inkwell::module::Linkage::External),
|
|
||||||
);
|
|
||||||
Function::set_default_attributes(llvm, mimic_call_byref, optimizer);
|
|
||||||
|
|
||||||
let r#return = Self::declare(
|
let r#return = Self::declare(
|
||||||
module,
|
module,
|
||||||
Self::FUNCTION_RETURN,
|
Self::FUNCTION_RETURN,
|
||||||
@@ -454,9 +270,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
|||||||
Function::set_default_attributes(llvm, revert, optimizer);
|
Function::set_default_attributes(llvm, revert, optimizer);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
personality,
|
|
||||||
cxa_throw,
|
|
||||||
|
|
||||||
shl,
|
shl,
|
||||||
shr,
|
shr,
|
||||||
sar,
|
sar,
|
||||||
@@ -469,18 +282,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
|||||||
|
|
||||||
sha3,
|
sha3,
|
||||||
|
|
||||||
system_request,
|
|
||||||
|
|
||||||
//far_call,
|
|
||||||
static_call,
|
|
||||||
delegate_call,
|
|
||||||
mimic_call,
|
|
||||||
|
|
||||||
far_call_byref,
|
|
||||||
static_call_byref,
|
|
||||||
delegate_call_byref,
|
|
||||||
mimic_call_byref,
|
|
||||||
|
|
||||||
r#return,
|
r#return,
|
||||||
revert,
|
revert,
|
||||||
}
|
}
|
||||||
@@ -506,42 +307,4 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
|||||||
value.set_linkage(inkwell::module::Linkage::External);
|
value.set_linkage(inkwell::module::Linkage::External);
|
||||||
FunctionDeclaration::new(value.get_type(), value).into()
|
FunctionDeclaration::new(value.get_type(), value).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modifies the external call function with `is_byref` and `is_system` modifiers.
|
|
||||||
pub fn modify(
|
|
||||||
&self,
|
|
||||||
function: FunctionDeclaration<'ctx>,
|
|
||||||
is_byref: bool,
|
|
||||||
) -> anyhow::Result<FunctionDeclaration<'ctx>> {
|
|
||||||
let modified = if
|
|
||||||
/*function == self.far_call {
|
|
||||||
match is_byref {
|
|
||||||
false => self.far_call,
|
|
||||||
true => self.far_call_byref,
|
|
||||||
}
|
|
||||||
} else if */
|
|
||||||
function == self.static_call {
|
|
||||||
match is_byref {
|
|
||||||
false => self.static_call,
|
|
||||||
true => self.static_call_byref,
|
|
||||||
}
|
|
||||||
} else if function == self.delegate_call {
|
|
||||||
match is_byref {
|
|
||||||
false => self.delegate_call,
|
|
||||||
true => self.delegate_call_byref,
|
|
||||||
}
|
|
||||||
} else if function == self.mimic_call {
|
|
||||||
match is_byref {
|
|
||||||
false => self.mimic_call,
|
|
||||||
true => self.mimic_call_byref,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Cannot modify an external call function `{}`",
|
|
||||||
function.value.get_name().to_string_lossy()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(modified)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,244 +0,0 @@
|
|||||||
//! The `default_call` function.
|
|
||||||
|
|
||||||
use inkwell::types::BasicType;
|
|
||||||
|
|
||||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
|
||||||
use crate::polkavm::context::function::llvm_runtime::LLVMRuntime;
|
|
||||||
use crate::polkavm::context::function::Function;
|
|
||||||
use crate::polkavm::context::Context;
|
|
||||||
use crate::polkavm::Dependency;
|
|
||||||
use crate::polkavm::WriteLLVM;
|
|
||||||
|
|
||||||
/// The `default_call` function.
|
|
||||||
/// Generates a default contract call, if the `msg.value` is zero.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DefaultCall {
|
|
||||||
/// The name of the inner function used for the low-level call.
|
|
||||||
inner_name: String,
|
|
||||||
/// The function name with the low-level function name as an element.
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
impl DefaultCall {
|
|
||||||
/// The gas argument index.
|
|
||||||
pub const ARGUMENT_INDEX_GAS: usize = 0;
|
|
||||||
|
|
||||||
/// The address argument index.
|
|
||||||
pub const ARGUMENT_INDEX_ADDRESS: usize = 1;
|
|
||||||
|
|
||||||
/// The input offset argument index.
|
|
||||||
pub const ARGUMENT_INDEX_INPUT_OFFSET: usize = 2;
|
|
||||||
|
|
||||||
/// The input length argument index.
|
|
||||||
pub const ARGUMENT_INDEX_INPUT_LENGTH: usize = 3;
|
|
||||||
|
|
||||||
/// The output offset argument index.
|
|
||||||
pub const ARGUMENT_INDEX_OUTPUT_OFFSET: usize = 4;
|
|
||||||
|
|
||||||
/// The output length argument index.
|
|
||||||
pub const ARGUMENT_INDEX_OUTPUT_LENGTH: usize = 5;
|
|
||||||
|
|
||||||
/// A shortcut constructor.
|
|
||||||
pub fn new(call_function: FunctionDeclaration) -> Self {
|
|
||||||
let inner_name = call_function.value.get_name().to_string_lossy().to_string();
|
|
||||||
let name = Self::name(call_function);
|
|
||||||
|
|
||||||
Self { inner_name, name }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the function name.
|
|
||||||
pub fn name(call_function: FunctionDeclaration) -> String {
|
|
||||||
let suffix = match call_function.value.get_name().to_string_lossy() {
|
|
||||||
name if name == LLVMRuntime::FUNCTION_FARCALL => "far",
|
|
||||||
name if name == LLVMRuntime::FUNCTION_STATICCALL => "static",
|
|
||||||
name if name == LLVMRuntime::FUNCTION_DELEGATECALL => "delegate",
|
|
||||||
name => panic!("Invalid low-level call inner function `{name}`"),
|
|
||||||
};
|
|
||||||
format!("__default_{suffix}_call")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the low-level call function.
|
|
||||||
fn inner_function<'ctx, D>(&self, context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
match self.inner_name.as_str() {
|
|
||||||
//name if name == LLVMRuntime::FUNCTION_FARCALL => context.llvm_runtime().far_call,
|
|
||||||
name if name == LLVMRuntime::FUNCTION_STATICCALL => context.llvm_runtime().static_call,
|
|
||||||
name if name == LLVMRuntime::FUNCTION_DELEGATECALL => {
|
|
||||||
context.llvm_runtime().delegate_call
|
|
||||||
}
|
|
||||||
name => panic!("Invalid low-level call inner function `{name}`"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> WriteLLVM<D> for DefaultCall
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
|
||||||
let function_type = context.function_type(
|
|
||||||
vec![
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
context.word_type().as_basic_type_enum(),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let function = context.add_function(
|
|
||||||
self.name.as_str(),
|
|
||||||
function_type,
|
|
||||||
1,
|
|
||||||
Some(inkwell::module::Linkage::Private),
|
|
||||||
)?;
|
|
||||||
Function::set_frontend_runtime_attributes(
|
|
||||||
context.llvm,
|
|
||||||
function.borrow().declaration(),
|
|
||||||
&context.optimizer,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
|
||||||
context.set_current_function(self.name.as_str())?;
|
|
||||||
|
|
||||||
/*
|
|
||||||
let gas = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_GAS)
|
|
||||||
.into_int_value();
|
|
||||||
let address = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_ADDRESS)
|
|
||||||
.into_int_value();
|
|
||||||
let input_offset = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_INPUT_OFFSET)
|
|
||||||
.into_int_value();
|
|
||||||
let input_length = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_INPUT_LENGTH)
|
|
||||||
.into_int_value();
|
|
||||||
let output_offset = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_OUTPUT_OFFSET)
|
|
||||||
.into_int_value();
|
|
||||||
let output_length = context
|
|
||||||
.current_function()
|
|
||||||
.borrow()
|
|
||||||
.get_nth_param(Self::ARGUMENT_INDEX_OUTPUT_LENGTH)
|
|
||||||
.into_int_value();
|
|
||||||
*/
|
|
||||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
|
||||||
|
|
||||||
let status_code_result_pointer = context.build_alloca(
|
|
||||||
context.word_type(),
|
|
||||||
"contract_call_result_status_code_pointer",
|
|
||||||
);
|
|
||||||
/*
|
|
||||||
context.build_store(status_code_result_pointer, context.field_const(0));
|
|
||||||
|
|
||||||
let abi_data = crate::polkavm::utils::abi_data(
|
|
||||||
context,
|
|
||||||
input_offset,
|
|
||||||
input_length,
|
|
||||||
Some(gas),
|
|
||||||
AddressSpace::Heap,
|
|
||||||
false,
|
|
||||||
)?
|
|
||||||
.into_int_value();
|
|
||||||
|
|
||||||
let result = context
|
|
||||||
.build_call(
|
|
||||||
self.inner_function(context),
|
|
||||||
crate::polkavm::utils::external_call_arguments(
|
|
||||||
context,
|
|
||||||
abi_data.as_basic_value_enum(),
|
|
||||||
address,
|
|
||||||
vec![],
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.as_slice(),
|
|
||||||
"contract_call_external",
|
|
||||||
)
|
|
||||||
.expect("IntrinsicFunction always returns a flag");
|
|
||||||
|
|
||||||
let result_abi_data = context
|
|
||||||
.builder()
|
|
||||||
.build_extract_value(
|
|
||||||
result.into_struct_value(),
|
|
||||||
0,
|
|
||||||
"contract_call_external_result_abi_data",
|
|
||||||
)
|
|
||||||
.expect("Always exists");
|
|
||||||
let result_abi_data_pointer = Pointer::new(
|
|
||||||
context.byte_type(),
|
|
||||||
AddressSpace::Generic,
|
|
||||||
result_abi_data.into_pointer_value(),
|
|
||||||
);
|
|
||||||
let result_abi_data_casted = result_abi_data_pointer.cast(context.field_type());
|
|
||||||
|
|
||||||
let result_status_code_boolean = context
|
|
||||||
.builder()
|
|
||||||
.build_extract_value(
|
|
||||||
result.into_struct_value(),
|
|
||||||
1,
|
|
||||||
"contract_call_external_result_status_code_boolean",
|
|
||||||
)
|
|
||||||
.expect("Always exists");
|
|
||||||
let result_status_code = context.builder().build_int_z_extend_or_bit_cast(
|
|
||||||
result_status_code_boolean.into_int_value(),
|
|
||||||
context.field_type(),
|
|
||||||
"contract_call_external_result_status_code",
|
|
||||||
)?;
|
|
||||||
context.build_store(status_code_result_pointer, result_status_code);
|
|
||||||
|
|
||||||
let source = result_abi_data_casted;
|
|
||||||
|
|
||||||
let destination = Pointer::new_with_offset(
|
|
||||||
context,
|
|
||||||
AddressSpace::Heap,
|
|
||||||
context.byte_type(),
|
|
||||||
output_offset,
|
|
||||||
"contract_call_destination",
|
|
||||||
);
|
|
||||||
|
|
||||||
context.build_memcpy_return_data(
|
|
||||||
context.intrinsics().memory_copy_from_generic,
|
|
||||||
destination,
|
|
||||||
source,
|
|
||||||
output_length,
|
|
||||||
"contract_call_memcpy_from_child",
|
|
||||||
);
|
|
||||||
|
|
||||||
context.write_abi_pointer(
|
|
||||||
result_abi_data_pointer,
|
|
||||||
crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
|
|
||||||
);
|
|
||||||
context.write_abi_data_size(
|
|
||||||
result_abi_data_pointer,
|
|
||||||
crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
|
||||||
|
|
||||||
context.set_basic_block(context.current_function().borrow().return_block());
|
|
||||||
let status_code_result =
|
|
||||||
context.build_load(status_code_result_pointer, "contract_call_status_code")?;
|
|
||||||
context.build_return(Some(&status_code_result));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -153,7 +153,7 @@ impl Entry {
|
|||||||
context.integer_const(crate::polkavm::XLEN, Self::MAX_CALLDATA_SIZE as u64),
|
context.integer_const(crate::polkavm::XLEN, Self::MAX_CALLDATA_SIZE as u64),
|
||||||
)?;
|
)?;
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::INPUT,
|
runtime_api::imports::INPUT,
|
||||||
&[input_pointer_casted.into(), length_pointer_casted.into()],
|
&[input_pointer_casted.into(), length_pointer_casted.into()],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -215,11 +215,11 @@ impl Entry {
|
|||||||
.ok_or_else(|| anyhow::anyhow!("Contract runtime code not found"))?;
|
.ok_or_else(|| anyhow::anyhow!("Contract runtime code not found"))?;
|
||||||
|
|
||||||
context.set_basic_block(deploy_code_call_block);
|
context.set_basic_block(deploy_code_call_block);
|
||||||
context.build_invoke(deploy_code.borrow().declaration, &[], "deploy_code_call");
|
context.build_call(deploy_code.borrow().declaration, &[], "deploy_code_call");
|
||||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
||||||
|
|
||||||
context.set_basic_block(runtime_code_call_block);
|
context.set_basic_block(runtime_code_call_block);
|
||||||
context.build_invoke(runtime_code.borrow().declaration, &[], "runtime_code_call");
|
context.build_call(runtime_code.borrow().declaration, &[], "runtime_code_call");
|
||||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -235,7 +235,7 @@ where
|
|||||||
let entry_function_type = context.function_type(entry_arguments, 0, false);
|
let entry_function_type = context.function_type(entry_arguments, 0, false);
|
||||||
context.add_function(Runtime::FUNCTION_ENTRY, entry_function_type, 0, None)?;
|
context.add_function(Runtime::FUNCTION_ENTRY, entry_function_type, 0, None)?;
|
||||||
|
|
||||||
for symbol in runtime_api::EXPORTS {
|
for symbol in runtime_api::exports::EXPORTS {
|
||||||
context.declare_extern_function(symbol)?;
|
context.declare_extern_function(symbol)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ where
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.set_current_function(runtime_api::DEPLOY)?;
|
context.set_current_function(runtime_api::exports::DEPLOY)?;
|
||||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||||
|
|
||||||
assert!(context
|
assert!(context
|
||||||
@@ -268,7 +268,7 @@ where
|
|||||||
context.set_basic_block(context.current_function().borrow().return_block);
|
context.set_basic_block(context.current_function().borrow().return_block);
|
||||||
context.build_unreachable();
|
context.build_unreachable();
|
||||||
|
|
||||||
context.set_current_function(runtime_api::CALL)?;
|
context.set_current_function(runtime_api::exports::CALL)?;
|
||||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||||
|
|
||||||
assert!(context
|
assert!(context
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
//! The front-end runtime functions.
|
//! The front-end runtime functions.
|
||||||
|
|
||||||
pub mod default_call;
|
|
||||||
pub mod deploy_code;
|
pub mod deploy_code;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
pub mod runtime_code;
|
pub mod runtime_code;
|
||||||
|
|
||||||
use crate::polkavm::context::address_space::AddressSpace;
|
use crate::polkavm::context::address_space::AddressSpace;
|
||||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
|
||||||
use crate::polkavm::context::Context;
|
|
||||||
use crate::polkavm::Dependency;
|
|
||||||
use crate::polkavm::WriteLLVM;
|
|
||||||
|
|
||||||
use self::default_call::DefaultCall;
|
|
||||||
|
|
||||||
/// The front-end runtime functions.
|
/// The front-end runtime functions.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -35,40 +28,4 @@ impl Runtime {
|
|||||||
pub fn new(_address_space: AddressSpace) -> Self {
|
pub fn new(_address_space: AddressSpace) -> Self {
|
||||||
Self { _address_space }
|
Self { _address_space }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the corresponding runtime function.
|
|
||||||
pub fn default_call<'ctx, D>(
|
|
||||||
context: &Context<'ctx, D>,
|
|
||||||
call_function: FunctionDeclaration<'ctx>,
|
|
||||||
) -> FunctionDeclaration<'ctx>
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
context
|
|
||||||
.get_function(DefaultCall::name(call_function).as_str())
|
|
||||||
.expect("Always exists")
|
|
||||||
.borrow()
|
|
||||||
.declaration()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> WriteLLVM<D> for Runtime
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
|
||||||
//DefaultCall::new(context.llvm_runtime().far_call).declare(context)?;
|
|
||||||
DefaultCall::new(context.llvm_runtime().static_call).declare(context)?;
|
|
||||||
DefaultCall::new(context.llvm_runtime().delegate_call).declare(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
|
||||||
//DefaultCall::new(context.llvm_runtime().far_call).into_llvm(context)?;
|
|
||||||
DefaultCall::new(context.llvm_runtime().static_call).into_llvm(context)?;
|
|
||||||
DefaultCall::new(context.llvm_runtime().delegate_call).into_llvm(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ where
|
|||||||
)
|
)
|
||||||
.expect("the PolkaVM guest API module should be linkable");
|
.expect("the PolkaVM guest API module should be linkable");
|
||||||
|
|
||||||
for export in runtime_api::EXPORTS {
|
for export in runtime_api::exports::EXPORTS {
|
||||||
module
|
module
|
||||||
.get_function(export)
|
.get_function(export)
|
||||||
.expect("should be declared")
|
.expect("should be declared")
|
||||||
@@ -151,7 +151,7 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for import in runtime_api::IMPORTS {
|
for import in runtime_api::imports::IMPORTS {
|
||||||
module
|
module
|
||||||
.get_function(import)
|
.get_function(import)
|
||||||
.expect("should be declared")
|
.expect("should be declared")
|
||||||
@@ -433,8 +433,6 @@ where
|
|||||||
let entry_block = self.llvm.append_basic_block(value, "entry");
|
let entry_block = self.llvm.append_basic_block(value, "entry");
|
||||||
let return_block = self.llvm.append_basic_block(value, "return");
|
let return_block = self.llvm.append_basic_block(value, "return");
|
||||||
|
|
||||||
value.set_personality_function(self.llvm_runtime.personality.value);
|
|
||||||
|
|
||||||
let r#return = match return_values_length {
|
let r#return = match return_values_length {
|
||||||
0 => FunctionReturn::none(),
|
0 => FunctionReturn::none(),
|
||||||
1 => {
|
1 => {
|
||||||
@@ -705,7 +703,7 @@ where
|
|||||||
.build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer");
|
.build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer");
|
||||||
|
|
||||||
self.build_runtime_call(
|
self.build_runtime_call(
|
||||||
runtime_api::GET_STORAGE,
|
runtime_api::imports::GET_STORAGE,
|
||||||
&[
|
&[
|
||||||
storage_key_pointer_casted.into(),
|
storage_key_pointer_casted.into(),
|
||||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||||
@@ -809,7 +807,7 @@ where
|
|||||||
.build_store(storage_value_pointer.value, storage_value_value)?;
|
.build_store(storage_value_pointer.value, storage_value_value)?;
|
||||||
|
|
||||||
self.build_runtime_call(
|
self.build_runtime_call(
|
||||||
runtime_api::SET_STORAGE,
|
runtime_api::imports::SET_STORAGE,
|
||||||
&[
|
&[
|
||||||
storage_key_pointer_casted.into(),
|
storage_key_pointer_casted.into(),
|
||||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||||
@@ -957,106 +955,6 @@ where
|
|||||||
call_site_value.try_as_basic_value().left()
|
call_site_value.try_as_basic_value().left()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds an invoke.
|
|
||||||
/// Is defaulted to a call if there is no global exception handler.
|
|
||||||
pub fn build_invoke(
|
|
||||||
&self,
|
|
||||||
function: FunctionDeclaration<'ctx>,
|
|
||||||
arguments: &[inkwell::values::BasicValueEnum<'ctx>],
|
|
||||||
name: &str,
|
|
||||||
) -> Option<inkwell::values::BasicValueEnum<'ctx>> {
|
|
||||||
if !self
|
|
||||||
.functions
|
|
||||||
.contains_key(Function::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER)
|
|
||||||
{
|
|
||||||
return self.build_call(function, arguments, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
let return_pointer = if let Some(r#type) = function.r#type.get_return_type() {
|
|
||||||
let pointer = self.build_alloca(r#type, "invoke_return_pointer");
|
|
||||||
self.build_store(pointer, r#type.const_zero()).unwrap();
|
|
||||||
Some(pointer)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let success_block = self.append_basic_block("invoke_success_block");
|
|
||||||
let catch_block = self.append_basic_block("invoke_catch_block");
|
|
||||||
let current_block = self.basic_block();
|
|
||||||
|
|
||||||
self.set_basic_block(catch_block);
|
|
||||||
let landing_pad_type = self.structure_type(&[
|
|
||||||
self.llvm()
|
|
||||||
.ptr_type(AddressSpace::Stack.into())
|
|
||||||
.as_basic_type_enum(),
|
|
||||||
self.integer_type(revive_common::BIT_LENGTH_X32)
|
|
||||||
.as_basic_type_enum(),
|
|
||||||
]);
|
|
||||||
self.builder
|
|
||||||
.build_landing_pad(
|
|
||||||
landing_pad_type,
|
|
||||||
self.llvm_runtime.personality.value,
|
|
||||||
&[self
|
|
||||||
.llvm()
|
|
||||||
.ptr_type(AddressSpace::Stack.into())
|
|
||||||
.const_zero()
|
|
||||||
.as_basic_value_enum()],
|
|
||||||
false,
|
|
||||||
"invoke_catch_landing",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
crate::polkavm::utils::throw(self);
|
|
||||||
|
|
||||||
self.set_basic_block(current_block);
|
|
||||||
let call_site_value = self
|
|
||||||
.builder
|
|
||||||
.build_indirect_invoke(
|
|
||||||
function.r#type,
|
|
||||||
function.value.as_global_value().as_pointer_value(),
|
|
||||||
arguments,
|
|
||||||
success_block,
|
|
||||||
catch_block,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
self.modify_call_site_value(arguments, call_site_value, function);
|
|
||||||
|
|
||||||
self.set_basic_block(success_block);
|
|
||||||
if let (Some(return_pointer), Some(mut return_value)) =
|
|
||||||
(return_pointer, call_site_value.try_as_basic_value().left())
|
|
||||||
{
|
|
||||||
if let Some(return_type) = function.r#type.get_return_type() {
|
|
||||||
if return_type.is_pointer_type() {
|
|
||||||
return_value = self
|
|
||||||
.builder()
|
|
||||||
.build_int_to_ptr(
|
|
||||||
return_value.into_int_value(),
|
|
||||||
return_type.into_pointer_type(),
|
|
||||||
format!("{name}_invoke_return_pointer_casted").as_str(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.as_basic_value_enum();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.build_store(return_pointer, return_value).unwrap();
|
|
||||||
}
|
|
||||||
return_pointer.map(|pointer| self.build_load(pointer, "invoke_result").unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds an invoke of local call covered with an exception handler.
|
|
||||||
/// Yul does not the exception handling, so the user can declare a special handling function
|
|
||||||
/// called (see constant `ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER`. If the enclosed function
|
|
||||||
/// panics, the control flow will be transferred to the exception handler.
|
|
||||||
pub fn build_invoke_near_call_abi(
|
|
||||||
&self,
|
|
||||||
_function: FunctionDeclaration<'ctx>,
|
|
||||||
_arguments: Vec<inkwell::values::BasicValueEnum<'ctx>>,
|
|
||||||
_name: &str,
|
|
||||||
) -> Option<inkwell::values::BasicValueEnum<'ctx>> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds a memory copy call.
|
|
||||||
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
|
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
|
||||||
pub fn build_memcpy(
|
pub fn build_memcpy(
|
||||||
&self,
|
&self,
|
||||||
@@ -1132,7 +1030,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.build_runtime_call(
|
self.build_runtime_call(
|
||||||
runtime_api::RETURN,
|
runtime_api::imports::RETURN,
|
||||||
&[flags.into(), offset_pointer.into(), length_pointer.into()],
|
&[flags.into(), offset_pointer.into(), length_pointer.into()],
|
||||||
);
|
);
|
||||||
self.build_unreachable();
|
self.build_unreachable();
|
||||||
@@ -1396,6 +1294,13 @@ where
|
|||||||
self.llvm.custom_width_int_type(crate::polkavm::XLEN as u32)
|
self.llvm.custom_width_int_type(crate::polkavm::XLEN as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the register witdh sized type.
|
||||||
|
pub fn sentinel_pointer(&self) -> inkwell::values::PointerValue<'ctx> {
|
||||||
|
self.xlen_type()
|
||||||
|
.const_all_ones()
|
||||||
|
.const_to_pointer(self.llvm().ptr_type(Default::default()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the runtime value width sized type.
|
/// Returns the runtime value width sized type.
|
||||||
pub fn value_type(&self) -> inkwell::types::IntType<'ctx> {
|
pub fn value_type(&self) -> inkwell::types::IntType<'ctx> {
|
||||||
self.llvm
|
self.llvm
|
||||||
|
|||||||
@@ -3,17 +3,104 @@
|
|||||||
use inkwell::values::BasicValue;
|
use inkwell::values::BasicValue;
|
||||||
|
|
||||||
use crate::polkavm::context::argument::Argument;
|
use crate::polkavm::context::argument::Argument;
|
||||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
|
||||||
use crate::polkavm::context::Context;
|
use crate::polkavm::context::Context;
|
||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
|
use crate::polkavm_const::runtime_api;
|
||||||
|
|
||||||
|
static STATIC_CALL_FLAG: u32 = 0b0001_0000;
|
||||||
|
|
||||||
/// Translates a contract call.
|
/// Translates a contract call.
|
||||||
/// If the `simulation_address` is specified, the call is substituted with another instruction
|
///
|
||||||
/// according to the specification.
|
/// If the `simulation_address` is specified, the call is
|
||||||
|
/// substituted with another instruction according to the specification.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn default<'ctx, D>(
|
pub fn call<'ctx, D>(
|
||||||
|
context: &mut Context<'ctx, D>,
|
||||||
|
gas: inkwell::values::IntValue<'ctx>,
|
||||||
|
address: inkwell::values::IntValue<'ctx>,
|
||||||
|
value: Option<inkwell::values::IntValue<'ctx>>,
|
||||||
|
input_offset: inkwell::values::IntValue<'ctx>,
|
||||||
|
input_length: inkwell::values::IntValue<'ctx>,
|
||||||
|
output_offset: inkwell::values::IntValue<'ctx>,
|
||||||
|
output_length: inkwell::values::IntValue<'ctx>,
|
||||||
|
_constants: Vec<Option<num::BigUint>>,
|
||||||
|
static_call: bool,
|
||||||
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||||
|
where
|
||||||
|
D: Dependency + Clone,
|
||||||
|
{
|
||||||
|
let address_pointer = context.build_alloca(context.word_type(), "address_ptr");
|
||||||
|
context.build_store(address_pointer, address)?;
|
||||||
|
|
||||||
|
let value_pointer = if let Some(value) = value {
|
||||||
|
let value_pointer = context.build_alloca(context.value_type(), "value");
|
||||||
|
context.build_store(value_pointer, value)?;
|
||||||
|
value_pointer.value
|
||||||
|
} else {
|
||||||
|
context.sentinel_pointer()
|
||||||
|
};
|
||||||
|
|
||||||
|
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
||||||
|
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
||||||
|
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
|
||||||
|
let output_length = context.safe_truncate_int_to_xlen(output_length)?;
|
||||||
|
|
||||||
|
let gas = context
|
||||||
|
.builder()
|
||||||
|
.build_int_truncate(gas, context.integer_type(64), "gas")?;
|
||||||
|
|
||||||
|
let flags = if static_call { STATIC_CALL_FLAG } else { 0 };
|
||||||
|
|
||||||
|
let input_pointer = context.build_heap_gep(input_offset, input_length)?;
|
||||||
|
let output_pointer = context.build_heap_gep(output_offset, output_length)?;
|
||||||
|
|
||||||
|
let output_length_pointer = context.get_global(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?;
|
||||||
|
context.build_store(output_length_pointer.into(), output_length)?;
|
||||||
|
|
||||||
|
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||||
|
context.builder(),
|
||||||
|
pallet_contracts_pvm_llapi::calling_convention::call(context.llvm()),
|
||||||
|
"call_arguments",
|
||||||
|
)?
|
||||||
|
.next(context.xlen_type().const_int(flags as u64, false))?
|
||||||
|
.next(address_pointer.value)?
|
||||||
|
.next(gas)?
|
||||||
|
.skip()
|
||||||
|
.next(context.sentinel_pointer())?
|
||||||
|
.next(value_pointer)?
|
||||||
|
.next(input_pointer.value)?
|
||||||
|
.next(input_length)?
|
||||||
|
.next(output_pointer.value)?
|
||||||
|
.next(output_length_pointer.value)?
|
||||||
|
.done();
|
||||||
|
|
||||||
|
let name = runtime_api::imports::CALL;
|
||||||
|
let arguments = context.builder().build_ptr_to_int(
|
||||||
|
argument_pointer,
|
||||||
|
context.xlen_type(),
|
||||||
|
"argument_pointer",
|
||||||
|
)?;
|
||||||
|
let success = context
|
||||||
|
.build_runtime_call(name, &[arguments.into()])
|
||||||
|
.unwrap_or_else(|| panic!("{name} should return a value"))
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
|
let is_success = context.builder().build_int_compare(
|
||||||
|
inkwell::IntPredicate::EQ,
|
||||||
|
success,
|
||||||
|
context.xlen_type().const_zero(),
|
||||||
|
"is_success",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(context
|
||||||
|
.builder()
|
||||||
|
.build_int_z_extend(is_success, context.word_type(), "success")?
|
||||||
|
.as_basic_value_enum())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn delegate_call<'ctx, D>(
|
||||||
_context: &mut Context<'ctx, D>,
|
_context: &mut Context<'ctx, D>,
|
||||||
_function: FunctionDeclaration<'ctx>,
|
|
||||||
_gas: inkwell::values::IntValue<'ctx>,
|
_gas: inkwell::values::IntValue<'ctx>,
|
||||||
_address: inkwell::values::IntValue<'ctx>,
|
_address: inkwell::values::IntValue<'ctx>,
|
||||||
_value: Option<inkwell::values::IntValue<'ctx>>,
|
_value: Option<inkwell::values::IntValue<'ctx>>,
|
||||||
@@ -26,68 +113,7 @@ pub fn default<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
todo!();
|
todo!()
|
||||||
|
|
||||||
/*
|
|
||||||
let ordinary_block = context.append_basic_block("contract_call_ordinary_block");
|
|
||||||
let join_block = context.append_basic_block("contract_call_join_block");
|
|
||||||
|
|
||||||
let result_pointer = context.build_alloca(context.field_type(), "contract_call_result_pointer");
|
|
||||||
context.build_store(result_pointer, context.field_const(0));
|
|
||||||
|
|
||||||
context.builder().build_switch(
|
|
||||||
address,
|
|
||||||
ordinary_block,
|
|
||||||
&[(
|
|
||||||
context.field_const(zkevm_opcode_defs::ADDRESS_IDENTITY.into()),
|
|
||||||
identity_block,
|
|
||||||
)],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
context.set_basic_block(identity_block);
|
|
||||||
let result = identity(context, output_offset, input_offset, output_length)?;
|
|
||||||
context.build_store(result_pointer, result);
|
|
||||||
context.build_unconditional_branch(join_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.set_basic_block(ordinary_block);
|
|
||||||
let result = if let Some(value) = value {
|
|
||||||
default_wrapped(
|
|
||||||
context,
|
|
||||||
function,
|
|
||||||
gas,
|
|
||||||
value,
|
|
||||||
address,
|
|
||||||
input_offset,
|
|
||||||
input_length,
|
|
||||||
output_offset,
|
|
||||||
output_length,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
let function = Runtime::default_call(context, function);
|
|
||||||
context
|
|
||||||
.build_call(
|
|
||||||
function,
|
|
||||||
&[
|
|
||||||
gas.as_basic_value_enum(),
|
|
||||||
address.as_basic_value_enum(),
|
|
||||||
input_offset.as_basic_value_enum(),
|
|
||||||
input_length.as_basic_value_enum(),
|
|
||||||
output_offset.as_basic_value_enum(),
|
|
||||||
output_length.as_basic_value_enum(),
|
|
||||||
],
|
|
||||||
"default_call",
|
|
||||||
)
|
|
||||||
.expect("Always exists")
|
|
||||||
};
|
|
||||||
context.build_store(result_pointer, result);
|
|
||||||
context.build_unconditional_branch(join_block);
|
|
||||||
|
|
||||||
context.set_basic_block(join_block);
|
|
||||||
let result = context.build_load(result_pointer, "contract_call_result");
|
|
||||||
Ok(result)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the Yul `linkersymbol` instruction.
|
/// Translates the Yul `linkersymbol` instruction.
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ where
|
|||||||
"block_timestamp_output",
|
"block_timestamp_output",
|
||||||
);
|
);
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::BLOCK_NUMBER,
|
runtime_api::imports::BLOCK_NUMBER,
|
||||||
&[
|
&[
|
||||||
output_pointer.to_int(context).into(),
|
output_pointer.to_int(context).into(),
|
||||||
output_length_pointer.to_int(context).into(),
|
output_length_pointer.to_int(context).into(),
|
||||||
@@ -83,7 +83,7 @@ where
|
|||||||
"block_timestamp_output",
|
"block_timestamp_output",
|
||||||
);
|
);
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::NOW,
|
runtime_api::imports::NOW,
|
||||||
&[
|
&[
|
||||||
output_pointer.to_int(context).into(),
|
output_pointer.to_int(context).into(),
|
||||||
output_length_pointer.to_int(context).into(),
|
output_length_pointer.to_int(context).into(),
|
||||||
@@ -174,7 +174,7 @@ where
|
|||||||
let (output_pointer, output_length_pointer) =
|
let (output_pointer, output_length_pointer) =
|
||||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::ADDRESS,
|
runtime_api::imports::ADDRESS,
|
||||||
&[
|
&[
|
||||||
output_pointer.to_int(context).into(),
|
output_pointer.to_int(context).into(),
|
||||||
output_length_pointer.to_int(context).into(),
|
output_length_pointer.to_int(context).into(),
|
||||||
@@ -197,7 +197,7 @@ where
|
|||||||
let (output_pointer, output_length_pointer) =
|
let (output_pointer, output_length_pointer) =
|
||||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::CALLER,
|
runtime_api::imports::CALLER,
|
||||||
&[
|
&[
|
||||||
output_pointer.to_int(context).into(),
|
output_pointer.to_int(context).into(),
|
||||||
output_length_pointer.to_int(context).into(),
|
output_length_pointer.to_int(context).into(),
|
||||||
|
|||||||
@@ -56,11 +56,7 @@ where
|
|||||||
|
|
||||||
let (address_pointer, address_length_pointer) =
|
let (address_pointer, address_length_pointer) =
|
||||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_pointer");
|
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_pointer");
|
||||||
|
context.build_store(address_pointer, context.word_const(0))?;
|
||||||
let sentinel = context
|
|
||||||
.xlen_type()
|
|
||||||
.const_all_ones()
|
|
||||||
.const_to_pointer(context.llvm().ptr_type(Default::default()));
|
|
||||||
|
|
||||||
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||||
context.builder(),
|
context.builder(),
|
||||||
@@ -70,14 +66,14 @@ where
|
|||||||
.next(code_hash_pointer.value)?
|
.next(code_hash_pointer.value)?
|
||||||
.skip()
|
.skip()
|
||||||
.skip()
|
.skip()
|
||||||
.next(sentinel)?
|
.next(context.sentinel_pointer())?
|
||||||
.next(value_pointer.value)?
|
.next(value_pointer.value)?
|
||||||
.next(input_data_pointer.value)?
|
.next(input_data_pointer.value)?
|
||||||
.next(input_length)?
|
.next(input_length)?
|
||||||
.next(address_pointer.value)?
|
.next(address_pointer.value)?
|
||||||
.next(address_length_pointer.value)?
|
.next(address_length_pointer.value)?
|
||||||
.next(sentinel)?
|
.next(context.sentinel_pointer())?
|
||||||
.next(sentinel)?
|
.next(context.sentinel_pointer())?
|
||||||
.next(salt_pointer.value)?
|
.next(salt_pointer.value)?
|
||||||
.next(
|
.next(
|
||||||
context
|
context
|
||||||
@@ -86,14 +82,13 @@ where
|
|||||||
)?
|
)?
|
||||||
.done();
|
.done();
|
||||||
|
|
||||||
context.builder().build_direct_call(
|
context.build_runtime_call(
|
||||||
context.runtime_api_method(runtime_api::INSTANTIATE),
|
runtime_api::imports::INSTANTIATE,
|
||||||
&[context
|
&[context
|
||||||
.builder()
|
.builder()
|
||||||
.build_ptr_to_int(argument_pointer, context.xlen_type(), "argument_pointer")?
|
.build_ptr_to_int(argument_pointer, context.xlen_type(), "argument_pointer")?
|
||||||
.into()],
|
.into()],
|
||||||
"create2",
|
);
|
||||||
)?;
|
|
||||||
|
|
||||||
context.build_load_word(
|
context.build_load_word(
|
||||||
address_pointer,
|
address_pointer,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ where
|
|||||||
let output_pointer = context.build_alloca(context.word_type(), "output_pointer");
|
let output_pointer = context.build_alloca(context.word_type(), "output_pointer");
|
||||||
|
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::HASH_KECCAK_256,
|
runtime_api::imports::HASH_KECCAK_256,
|
||||||
&[
|
&[
|
||||||
input_pointer.to_int(context).into(),
|
input_pointer.to_int(context).into(),
|
||||||
length_casted.into(),
|
length_casted.into(),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ where
|
|||||||
let (output_pointer, output_length_pointer) =
|
let (output_pointer, output_length_pointer) =
|
||||||
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
|
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
|
||||||
context.build_runtime_call(
|
context.build_runtime_call(
|
||||||
runtime_api::VALUE_TRANSFERRED,
|
runtime_api::imports::VALUE_TRANSFERRED,
|
||||||
&[
|
&[
|
||||||
output_pointer.to_int(context).into(),
|
output_pointer.to_int(context).into(),
|
||||||
output_length_pointer.to_int(context).into(),
|
output_length_pointer.to_int(context).into(),
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ where
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = context.build_runtime_call(runtime_api::DEPOSIT_EVENT, &arguments);
|
let _ = context.build_runtime_call(runtime_api::imports::DEPOSIT_EVENT, &arguments);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ where
|
|||||||
"address_pointer",
|
"address_pointer",
|
||||||
)?;
|
)?;
|
||||||
let value = context
|
let value = context
|
||||||
.build_runtime_call(runtime_api::CODE_SIZE, &[address_pointer_casted.into()])
|
.build_runtime_call(
|
||||||
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::CODE_SIZE))
|
runtime_api::imports::CODE_SIZE,
|
||||||
|
&[address_pointer_casted.into()],
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::imports::CODE_SIZE))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
|
|
||||||
Ok(context
|
Ok(context
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use inkwell::values::BasicValue;
|
|||||||
|
|
||||||
use crate::polkavm::context::Context;
|
use crate::polkavm::context::Context;
|
||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
|
use crate::polkavm_const::runtime_api;
|
||||||
|
|
||||||
/// Translates the return data size.
|
/// Translates the return data size.
|
||||||
pub fn size<'ctx, D>(
|
pub fn size<'ctx, D>(
|
||||||
@@ -38,54 +39,16 @@ where
|
|||||||
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
||||||
let size = context.safe_truncate_int_to_xlen(size)?;
|
let size = context.safe_truncate_int_to_xlen(size)?;
|
||||||
|
|
||||||
let block_copy = context.append_basic_block("copy_block");
|
let destination_offset = context.builder().build_ptr_to_int(
|
||||||
let block_trap = context.append_basic_block("trap_block");
|
context.build_heap_gep(destination_offset, size)?.value,
|
||||||
let block_check_out_of_bounds = context.append_basic_block("check_out_of_bounds_block");
|
context.xlen_type(),
|
||||||
let is_overflow = context.builder().build_int_compare(
|
"destination_offset",
|
||||||
inkwell::IntPredicate::UGT,
|
|
||||||
source_offset,
|
|
||||||
context.builder().build_int_sub(
|
|
||||||
context.xlen_type().const_all_ones(),
|
|
||||||
size,
|
|
||||||
"offset_plus_size_max_value",
|
|
||||||
)?,
|
|
||||||
"is_returndata_size_out_of_bounds",
|
|
||||||
)?;
|
)?;
|
||||||
context.build_conditional_branch(is_overflow, block_trap, block_check_out_of_bounds)?;
|
|
||||||
|
|
||||||
context.set_basic_block(block_check_out_of_bounds);
|
context.build_runtime_call(
|
||||||
let is_out_of_bounds = context.builder().build_int_compare(
|
runtime_api::imports::RETURNDATACOPY,
|
||||||
inkwell::IntPredicate::UGT,
|
&[destination_offset.into(), source_offset.into(), size.into()],
|
||||||
context.builder().build_int_add(
|
);
|
||||||
source_offset,
|
|
||||||
context
|
|
||||||
.get_global_value(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?
|
|
||||||
.into_int_value(),
|
|
||||||
"returndata_end_pointer",
|
|
||||||
)?,
|
|
||||||
context
|
|
||||||
.xlen_type()
|
|
||||||
.const_int(crate::PolkaVMEntryFunction::MAX_CALLDATA_SIZE as u64, false),
|
|
||||||
"is_return_data_copy_overflow",
|
|
||||||
)?;
|
|
||||||
context.build_conditional_branch(is_out_of_bounds, block_trap, block_copy)?;
|
|
||||||
|
|
||||||
context.set_basic_block(block_trap);
|
Ok(())
|
||||||
context.build_call(context.intrinsics().trap, &[], "invalid_returndata_copy");
|
|
||||||
context.build_unreachable();
|
|
||||||
|
|
||||||
context.set_basic_block(block_copy);
|
|
||||||
context.build_memcpy(
|
|
||||||
context.build_heap_gep(destination_offset, size)?,
|
|
||||||
context.build_gep(
|
|
||||||
context
|
|
||||||
.get_global(crate::polkavm::GLOBAL_RETURN_DATA_POINTER)?
|
|
||||||
.into(),
|
|
||||||
&[context.xlen_type().const_zero(), source_offset],
|
|
||||||
context.byte_type(),
|
|
||||||
"source_offset_gep",
|
|
||||||
),
|
|
||||||
size,
|
|
||||||
"return_data_copy_memcpy_from_return_data",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
use inkwell::values::BasicValue;
|
use inkwell::values::BasicValue;
|
||||||
|
|
||||||
use crate::polkavm::context::address_space::AddressSpace;
|
use crate::polkavm::context::address_space::AddressSpace;
|
||||||
use crate::polkavm::context::function::llvm_runtime::LLVMRuntime;
|
|
||||||
use crate::polkavm::context::Context;
|
use crate::polkavm::context::Context;
|
||||||
use crate::polkavm::Dependency;
|
use crate::polkavm::Dependency;
|
||||||
|
|
||||||
@@ -40,23 +39,6 @@ where
|
|||||||
Ok(result.into_int_value())
|
Ok(result.into_int_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an exception.
|
|
||||||
pub fn throw<D>(context: &Context<D>)
|
|
||||||
where
|
|
||||||
D: Dependency + Clone,
|
|
||||||
{
|
|
||||||
context.build_call(
|
|
||||||
context.llvm_runtime().cxa_throw,
|
|
||||||
&[context
|
|
||||||
.llvm()
|
|
||||||
.ptr_type(AddressSpace::Stack.into())
|
|
||||||
.get_undef()
|
|
||||||
.as_basic_value_enum(); 3],
|
|
||||||
LLVMRuntime::FUNCTION_CXA_THROW,
|
|
||||||
);
|
|
||||||
context.build_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the full list of arguments for an external call.
|
/// Returns the full list of arguments for an external call.
|
||||||
/// Performs the extra ABI data padding and adds the mimic call extra argument.
|
/// Performs the extra ABI data padding and adds the mimic call extra argument.
|
||||||
pub fn external_call_arguments<'ctx, D>(
|
pub fn external_call_arguments<'ctx, D>(
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ use inkwell::{
|
|||||||
values::{BasicValue, PointerValue},
|
values::{BasicValue, PointerValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Spill<'ctx> {
|
pub struct Spill<'a, 'ctx> {
|
||||||
pointer: PointerValue<'ctx>,
|
pointer: PointerValue<'ctx>,
|
||||||
builder: &'ctx Builder<'ctx>,
|
builder: &'a Builder<'ctx>,
|
||||||
r#type: StructType<'ctx>,
|
r#type: StructType<'ctx>,
|
||||||
current_field: u32,
|
current_field: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Spill<'ctx> {
|
impl<'a, 'ctx> Spill<'a, 'ctx> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
builder: &'ctx Builder<'ctx>,
|
builder: &'a Builder<'ctx>,
|
||||||
r#type: StructType<'ctx>,
|
r#type: StructType<'ctx>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
@@ -88,3 +88,31 @@ pub fn instantiate(context: &Context) -> StructType {
|
|||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call(context: &Context) -> StructType {
|
||||||
|
context.struct_type(
|
||||||
|
&[
|
||||||
|
// flags: u32,
|
||||||
|
context.i32_type().as_basic_type_enum(),
|
||||||
|
// address_ptr:
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// ref_time_limit: u64,
|
||||||
|
context.i64_type().as_basic_type_enum(),
|
||||||
|
// proof_size_limit: u64,
|
||||||
|
context.i64_type().as_basic_type_enum(),
|
||||||
|
// deposit_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// value_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// input_data_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// input_data_len: u32,
|
||||||
|
context.i32_type().as_basic_type_enum(),
|
||||||
|
// output_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
// output_len_ptr: u32,
|
||||||
|
context.ptr_type(Default::default()).as_basic_type_enum(),
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ POLKAVM_IMPORT(void, input, uint32_t, uint32_t)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(void, seal_return, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, seal_return, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
|
POLKAVM_IMPORT(void, returndatacopy, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(void, value_transferred, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, value_transferred, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||||
|
|||||||
@@ -191,11 +191,6 @@ where
|
|||||||
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
||||||
entry.declare(context)?;
|
entry.declare(context)?;
|
||||||
|
|
||||||
let mut runtime = revive_llvm_context::PolkaVMRuntime::new(
|
|
||||||
revive_llvm_context::PolkaVMAddressSpace::Heap,
|
|
||||||
);
|
|
||||||
runtime.declare(context)?;
|
|
||||||
|
|
||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(
|
revive_llvm_context::PolkaVMDeployCodeFunction::new(
|
||||||
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
||||||
)
|
)
|
||||||
@@ -207,8 +202,6 @@ where
|
|||||||
|
|
||||||
entry.into_llvm(context)?;
|
entry.into_llvm(context)?;
|
||||||
|
|
||||||
runtime.into_llvm(context)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ where
|
|||||||
.integer_type(revive_common::BIT_LENGTH_BOOLEAN)
|
.integer_type(revive_common::BIT_LENGTH_BOOLEAN)
|
||||||
.const_int(0, false),
|
.const_int(0, false),
|
||||||
};
|
};
|
||||||
context.build_invoke(
|
context.build_call(
|
||||||
target,
|
target,
|
||||||
&[is_deploy_code.as_basic_value_enum()],
|
&[is_deploy_code.as_basic_value_enum()],
|
||||||
format!("call_link_{}", EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME).as_str(),
|
format!("call_link_{}", EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME).as_str(),
|
||||||
|
|||||||
@@ -1026,19 +1026,16 @@ where
|
|||||||
InstructionName::CALL => {
|
InstructionName::CALL => {
|
||||||
let mut arguments = self.pop_arguments_llvm(context);
|
let mut arguments = self.pop_arguments_llvm(context);
|
||||||
|
|
||||||
let _gas = arguments.remove(0).into_int_value();
|
let gas = arguments.remove(0).into_int_value();
|
||||||
let _address = arguments.remove(0).into_int_value();
|
let address = arguments.remove(0).into_int_value();
|
||||||
let _value = arguments.remove(0).into_int_value();
|
let value = arguments.remove(0).into_int_value();
|
||||||
let _input_offset = arguments.remove(0).into_int_value();
|
let input_offset = arguments.remove(0).into_int_value();
|
||||||
let _input_size = arguments.remove(0).into_int_value();
|
let input_size = arguments.remove(0).into_int_value();
|
||||||
let _output_offset = arguments.remove(0).into_int_value();
|
let output_offset = arguments.remove(0).into_int_value();
|
||||||
let _output_size = arguments.remove(0).into_int_value();
|
let output_size = arguments.remove(0).into_int_value();
|
||||||
|
|
||||||
todo!()
|
revive_llvm_context::polkavm_evm_call::call(
|
||||||
/*
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().far_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
Some(value),
|
Some(value),
|
||||||
@@ -1047,9 +1044,9 @@ where
|
|||||||
output_offset,
|
output_offset,
|
||||||
output_size,
|
output_size,
|
||||||
vec![],
|
vec![],
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
InstructionName::STATICCALL => {
|
InstructionName::STATICCALL => {
|
||||||
let mut arguments = self.pop_arguments_llvm(context);
|
let mut arguments = self.pop_arguments_llvm(context);
|
||||||
@@ -1061,9 +1058,8 @@ where
|
|||||||
let output_offset = arguments.remove(0).into_int_value();
|
let output_offset = arguments.remove(0).into_int_value();
|
||||||
let output_size = arguments.remove(0).into_int_value();
|
let output_size = arguments.remove(0).into_int_value();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
revive_llvm_context::polkavm_evm_call::call(
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().static_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
None,
|
||||||
@@ -1072,6 +1068,7 @@ where
|
|||||||
output_offset,
|
output_offset,
|
||||||
output_size,
|
output_size,
|
||||||
vec![],
|
vec![],
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
@@ -1085,9 +1082,8 @@ where
|
|||||||
let output_offset = arguments.remove(0).into_int_value();
|
let output_offset = arguments.remove(0).into_int_value();
|
||||||
let output_size = arguments.remove(0).into_int_value();
|
let output_size = arguments.remove(0).into_int_value();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
revive_llvm_context::polkavm_evm_call::delegate_call(
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().delegate_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ impl FunctionCall {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = context.build_invoke(
|
let return_value = context.build_call(
|
||||||
function.borrow().declaration(),
|
function.borrow().declaration(),
|
||||||
values.as_slice(),
|
values.as_slice(),
|
||||||
format!("{name}_call").as_str(),
|
format!("{name}_call").as_str(),
|
||||||
@@ -731,24 +731,21 @@ impl FunctionCall {
|
|||||||
Name::Call => {
|
Name::Call => {
|
||||||
let arguments = self.pop_arguments::<D, 7>(context)?;
|
let arguments = self.pop_arguments::<D, 7>(context)?;
|
||||||
|
|
||||||
let _gas = arguments[0].value.into_int_value();
|
let gas = arguments[0].value.into_int_value();
|
||||||
let _address = arguments[1].value.into_int_value();
|
let address = arguments[1].value.into_int_value();
|
||||||
let _value = arguments[2].value.into_int_value();
|
let value = arguments[2].value.into_int_value();
|
||||||
let _input_offset = arguments[3].value.into_int_value();
|
let input_offset = arguments[3].value.into_int_value();
|
||||||
let _input_size = arguments[4].value.into_int_value();
|
let input_size = arguments[4].value.into_int_value();
|
||||||
let _output_offset = arguments[5].value.into_int_value();
|
let output_offset = arguments[5].value.into_int_value();
|
||||||
let _output_size = arguments[6].value.into_int_value();
|
let output_size = arguments[6].value.into_int_value();
|
||||||
|
|
||||||
let _simulation_address: Vec<Option<num::BigUint>> = arguments
|
let simulation_address: Vec<Option<num::BigUint>> = arguments
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut argument| argument.constant.take())
|
.map(|mut argument| argument.constant.take())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
todo!()
|
revive_llvm_context::polkavm_evm_call::call(
|
||||||
/*
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().far_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
Some(value),
|
Some(value),
|
||||||
@@ -757,9 +754,9 @@ impl FunctionCall {
|
|||||||
output_offset,
|
output_offset,
|
||||||
output_size,
|
output_size,
|
||||||
simulation_address,
|
simulation_address,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
Name::StaticCall => {
|
Name::StaticCall => {
|
||||||
let arguments = self.pop_arguments::<D, 6>(context)?;
|
let arguments = self.pop_arguments::<D, 6>(context)?;
|
||||||
@@ -776,9 +773,8 @@ impl FunctionCall {
|
|||||||
.map(|mut argument| argument.constant.take())
|
.map(|mut argument| argument.constant.take())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
revive_llvm_context::polkavm_evm_call::call(
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().static_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
None,
|
||||||
@@ -787,6 +783,7 @@ impl FunctionCall {
|
|||||||
output_offset,
|
output_offset,
|
||||||
output_size,
|
output_size,
|
||||||
simulation_address,
|
simulation_address,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
@@ -805,9 +802,8 @@ impl FunctionCall {
|
|||||||
.map(|mut argument| argument.constant.take())
|
.map(|mut argument| argument.constant.take())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
revive_llvm_context::polkavm_evm_call::default(
|
revive_llvm_context::polkavm_evm_call::delegate_call(
|
||||||
context,
|
context,
|
||||||
context.llvm_runtime().delegate_call,
|
|
||||||
gas,
|
gas,
|
||||||
address,
|
address,
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -186,11 +186,6 @@ where
|
|||||||
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
||||||
entry.declare(context)?;
|
entry.declare(context)?;
|
||||||
|
|
||||||
let mut runtime = revive_llvm_context::PolkaVMRuntime::new(
|
|
||||||
revive_llvm_context::PolkaVMAddressSpace::Heap,
|
|
||||||
);
|
|
||||||
runtime.declare(context)?;
|
|
||||||
|
|
||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(
|
revive_llvm_context::PolkaVMDeployCodeFunction::new(
|
||||||
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
revive_llvm_context::PolkaVMDummyLLVMWritable::default(),
|
||||||
)
|
)
|
||||||
@@ -226,16 +221,8 @@ where
|
|||||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.inner_object {
|
if let Some(object) = self.inner_object {
|
||||||
Some(object) => {
|
object.into_llvm(context)?;
|
||||||
object.into_llvm(context)?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let runtime = revive_llvm_context::PolkaVMRuntime::new(
|
|
||||||
revive_llvm_context::PolkaVMAddressSpace::Heap,
|
|
||||||
);
|
|
||||||
runtime.into_llvm(context)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user