Skip to content

Commit b846378

Browse files
committed
Baby steps
The current changes allow me to compile the Solidity program below, and the resulting wasm file passes `cargo stylus --check`. ```sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract Counter { uint256 public number; function setNumber(uint256 newNumber) public { number = newNumber; } function increment() public { number++; } } ```
1 parent f829db3 commit b846378

File tree

6 files changed

+680
-4
lines changed

6 files changed

+680
-4
lines changed

src/codegen/dispatch/polkadot.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub(crate) fn function_dispatch(
6969
]
7070
}
7171

72-
struct Dispatch<'a> {
72+
pub(super) struct Dispatch<'a> {
7373
start: usize,
7474
input_len: usize,
7575
input_ptr: Expression,
@@ -110,7 +110,7 @@ impl<'a> Dispatch<'a> {
110110
/// Create a new `Dispatch` struct that has all the data needed for building the dispatch logic.
111111
///
112112
/// `ty` specifies whether to include constructors or functions.
113-
fn new(
113+
pub(super) fn new(
114114
all_cfg: &'a [ControlFlowGraph],
115115
ns: &'a mut Namespace,
116116
opt: &'a Options,
@@ -195,7 +195,7 @@ impl<'a> Dispatch<'a> {
195195
}
196196

197197
/// Build the dispatch logic into the returned control flow graph.
198-
fn build(mut self) -> ControlFlowGraph {
198+
pub(super) fn build(mut self) -> ControlFlowGraph {
199199
// Go to fallback or receive if there is no selector in the call input
200200
let cond = Expression::Less {
201201
loc: Codegen,

src/codegen/dispatch/stylus.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
use super::polkadot;
4+
use crate::{
5+
codegen::{cfg::ControlFlowGraph, Options},
6+
sema::ast::Namespace,
7+
};
8+
use solang_parser::pt::FunctionTy;
9+
10+
pub(crate) fn function_dispatch(
11+
_contract_no: usize,
12+
all_cfg: &[ControlFlowGraph],
13+
ns: &mut Namespace,
14+
opt: &Options,
15+
) -> Vec<ControlFlowGraph> {
16+
vec![polkadot::Dispatch::new(all_cfg, ns, opt, FunctionTy::Function).build()]
17+
}

src/emit/binary.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ macro_rules! emit_context {
5353
#[allow(unused_macros)]
5454
macro_rules! byte_ptr {
5555
() => {
56-
$binary.context.i8_type().ptr_type(AddressSpace::default())
56+
$binary
57+
.context
58+
.i8_type()
59+
.ptr_type(inkwell::AddressSpace::default())
5760
};
5861
}
5962

src/emit/stylus/mod.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
use crate::codegen::dispatch::polkadot::DispatchType;
4+
use crate::codegen::Options;
5+
use crate::emit::functions::emit_functions;
6+
use crate::emit::Binary;
7+
use crate::emit_context;
8+
use crate::sema::ast::{Contract, Namespace};
9+
use inkwell::context::Context;
10+
use inkwell::module::{Linkage, Module};
11+
use inkwell::values::{BasicMetadataValueEnum, FunctionValue, IntValue, PointerValue};
12+
use inkwell::AddressSpace;
13+
14+
mod target;
15+
16+
pub struct StylusTarget;
17+
18+
impl StylusTarget {
19+
pub fn build<'a>(
20+
context: &'a Context,
21+
std_lib: &Module<'a>,
22+
contract: &'a Contract,
23+
ns: &'a Namespace,
24+
opt: &'a Options,
25+
) -> Binary<'a> {
26+
let filename = ns.files[contract.loc.file_no()].file_name();
27+
let mut binary = Binary::new(
28+
context,
29+
ns.target,
30+
&contract.id.name,
31+
filename.as_str(),
32+
opt,
33+
std_lib,
34+
None,
35+
);
36+
37+
let mut target = StylusTarget;
38+
39+
target.declare_externals(&binary);
40+
41+
emit_functions(&mut target, &mut binary, contract, ns);
42+
43+
target.emit_dispatch(&mut binary, ns);
44+
45+
binary.internalize(&[
46+
"log_txt",
47+
"msg_reentrant",
48+
"msg_value",
49+
"pay_for_memory_grow",
50+
"read_args",
51+
"storage_flush_cache",
52+
"storage_cache_bytes32",
53+
"storage_load_bytes32",
54+
"write_result",
55+
]);
56+
57+
binary
58+
}
59+
60+
fn public_function_prelude<'a>(
61+
&self,
62+
binary: &Binary<'a>,
63+
function: FunctionValue<'a>,
64+
) -> (PointerValue<'a>, IntValue<'a>) {
65+
emit_context!(binary);
66+
67+
let entry = binary.context.append_basic_block(function, "entry");
68+
69+
binary.builder.position_at_end(entry);
70+
71+
// init our heap
72+
binary
73+
.builder
74+
.build_call(
75+
binary.module.get_function("__init_heap").unwrap(),
76+
&[],
77+
"__init_heap",
78+
)
79+
.unwrap();
80+
81+
let args_len = function.get_nth_param(0).unwrap();
82+
83+
let args = call!("__malloc", &[args_len.into()], "__malloc")
84+
.try_as_basic_value()
85+
.left()
86+
.unwrap();
87+
88+
call!("read_args", &[args.into()], "read_args");
89+
90+
(args.into_pointer_value(), args_len.into_int_value())
91+
}
92+
93+
fn declare_externals(&self, binary: &Binary) {
94+
let ctx = binary.context;
95+
let i32_val = ctx.i32_type().into();
96+
let u8_ptr = ctx.i8_type().ptr_type(AddressSpace::default()).into();
97+
98+
macro_rules! external {
99+
($name:literal, $fn_type:ident $(,)? $( $args:expr ),*) => {
100+
binary.module.add_function(
101+
$name,
102+
ctx.$fn_type().fn_type(&[$($args),*], false),
103+
Some(Linkage::External),
104+
);
105+
};
106+
}
107+
108+
external!("log_txt", void_type, u8_ptr, i32_val);
109+
external!("msg_reentrant", i32_type);
110+
external!("msg_value", void_type, i32_val);
111+
external!("pay_for_memory_grow", void_type, i32_val);
112+
external!("read_args", void_type, u8_ptr);
113+
external!("storage_cache_bytes32", void_type, u8_ptr, u8_ptr);
114+
external!("storage_flush_cache", void_type, i32_val);
115+
external!("storage_load_bytes32", void_type, u8_ptr, u8_ptr);
116+
external!("write_result", void_type, u8_ptr, i32_val);
117+
}
118+
119+
fn emit_dispatch(&mut self, bin: &mut Binary, _ns: &Namespace) {
120+
let ty = bin
121+
.context
122+
.i32_type()
123+
.fn_type(&[bin.context.i32_type().into()], false);
124+
let func = bin.module.add_function("user_entrypoint", ty, None);
125+
let (args, args_len) = self.public_function_prelude(bin, func);
126+
// smoelius: FIXME: zero
127+
let zero = bin.context.custom_width_int_type(256).const_zero();
128+
let args = &[
129+
BasicMetadataValueEnum::PointerValue(args),
130+
BasicMetadataValueEnum::IntValue(args_len),
131+
BasicMetadataValueEnum::IntValue(zero),
132+
BasicMetadataValueEnum::PointerValue(bin.selector.as_pointer_value()),
133+
];
134+
let dispatch_cfg_name = &DispatchType::Call.to_string();
135+
let cfg = bin.module.get_function(dispatch_cfg_name).unwrap();
136+
bin.builder
137+
.build_call(cfg, args, dispatch_cfg_name)
138+
.unwrap();
139+
140+
bin.builder.build_unreachable().unwrap();
141+
}
142+
}

0 commit comments

Comments
 (0)