Skip to content

Commit

Permalink
Merge 75bdad5 into 59dcc10
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Jun 10, 2024
2 parents 59dcc10 + 75bdad5 commit eeff563
Show file tree
Hide file tree
Showing 22 changed files with 386 additions and 141 deletions.
8 changes: 6 additions & 2 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1905,9 +1905,13 @@ pub fn compile(
if let ProgramABI::Fuel(ref mut program_abi) = program_abi {
if let Some(ref mut configurables) = program_abi.configurables {
// Filter out all dead configurables (i.e. ones without offsets in the bytecode)
configurables.retain(|c| compiled.config_const_offsets.contains_key(&c.name));
configurables.retain(|c| {
compiled
.named_data_section_entries_offsets
.contains_key(&c.name)
});
// Set the actual offsets in the JSON object
for (config, offset) in compiled.config_const_offsets {
for (config, offset) in compiled.named_data_section_entries_offsets {
if let Some(idx) = configurables.iter().position(|c| c.name == config) {
configurables[idx].offset = offset;
}
Expand Down
264 changes: 244 additions & 20 deletions sway-core/src/asm_generation/finalized_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::source_map::SourceMap;
use crate::BuildConfig;

use etk_asm::asm::Assembler;
use fuel_vm::fuel_asm::{Imm06, Imm12, Imm18, Imm24, Instruction, RegId};
use sway_error::error::CompileError;
use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::span::Span;
Expand Down Expand Up @@ -46,7 +47,7 @@ pub struct FinalizedEntry {
/// the bytecode.
pub struct CompiledBytecode {
pub bytecode: Vec<u8>,
pub config_const_offsets: BTreeMap<String, u64>,
pub named_data_section_entries_offsets: BTreeMap<String, u64>,
}

impl FinalizedAsm {
Expand All @@ -72,13 +73,13 @@ impl FinalizedAsm {
} else {
Ok(CompiledBytecode {
bytecode: assembler.take(),
config_const_offsets: BTreeMap::new(),
named_data_section_entries_offsets: BTreeMap::new(),
})
}
}
InstructionSet::MidenVM { ops } => Ok(CompiledBytecode {
bytecode: ops.to_bytecode().into(),
config_const_offsets: Default::default(),
named_data_section_entries_offsets: Default::default(),
}),
}
}
Expand Down Expand Up @@ -144,7 +145,7 @@ fn to_bytecode_mut(
&ops_padded
};

let mut buf = Vec::with_capacity(offset_to_data_section_in_bytes as usize);
let mut bytecode = Vec::with_capacity(offset_to_data_section_in_bytes as usize);

if build_config.print_bytecode {
println!(";; --- START OF TARGET BYTECODE ---\n");
Expand All @@ -164,23 +165,38 @@ fn to_bytecode_mut(
match fuel_op {
Either::Right(data) => {
if build_config.print_bytecode {
println!("{:?}", data);
print!("{:#010x} ", bytecode.len());
println!(
" ;; {:?}",
data
);
}

// Static assert to ensure that we're only dealing with DataSectionOffsetPlaceholder,
// a one-word (8 bytes) data within the code. No other uses are known.
let _: [u8; 8] = data;
buf.extend(data.iter().cloned());

bytecode.extend(data.iter().cloned());
half_word_ix += 2;
}
Either::Left(ops) => {
for op in ops {
Either::Left(instructions) => {
for instruction in instructions {
if build_config.print_bytecode {
println!("{:?}", op);
print!("{:#010x} ", bytecode.len());
print_instruction(&instruction);
}

if let Some(span) = &span {
source_map.insert(source_engine, half_word_ix, span);
}
buf.extend(op.to_bytes().iter());

let bytes = instruction.to_bytes();

if build_config.print_bytecode {
println!(";; {bytes:?}")
}

bytecode.extend(bytes.iter());
half_word_ix += 1;
}
}
Expand All @@ -192,26 +208,234 @@ fn to_bytecode_mut(
}

assert_eq!(half_word_ix * 4, offset_to_data_section_in_bytes as usize);
assert_eq!(buf.len(), offset_to_data_section_in_bytes as usize);
assert_eq!(bytecode.len(), offset_to_data_section_in_bytes as usize);

let config_offsets = data_section
.config_map
let named_data_section_entries_offsets = data_section
.value_pairs
.iter()
.map(|(name, id)| {
.enumerate()
.filter(|entry| entry.1.name.is_some())
.map(|(id, entry)| {
(
name.clone(),
offset_to_data_section_in_bytes + data_section.raw_data_id_to_offset(*id) as u64,
entry.name.as_ref().unwrap().clone(),
offset_to_data_section_in_bytes
+ data_section.raw_data_id_to_offset(id as u32) as u64,
)
})
.collect::<BTreeMap<String, u64>>();

let mut data_section = data_section.serialize_to_bytes();

buf.append(&mut data_section);
bytecode.append(&mut data_section);

CompiledBytecode {
bytecode: buf,
config_const_offsets: config_offsets,
bytecode,
named_data_section_entries_offsets,
}
}

// Code to pretty print bytecode
fn print_reg(r: RegId) -> String {
match r {
RegId::BAL => "$bal".to_string(),
RegId::CGAS => "$cgas".to_string(),
RegId::ERR => "$err".to_string(),
RegId::FLAG => "$flag".to_string(),
RegId::FP => "$fp".to_string(),
RegId::GGAS => "$ggas".to_string(),
RegId::HP => "$hp".to_string(),
RegId::IS => "$is".to_string(),
RegId::OF => "$of".to_string(),
RegId::ONE => "$one".to_string(),
RegId::PC => "$pc".to_string(),
RegId::RET => "$ret".to_string(),
RegId::RETL => "$retl".to_string(),
RegId::SP => "$sp".to_string(),
RegId::SSP => "$ssp".to_string(),
RegId::WRITABLE => "$writable".to_string(),
RegId::ZERO => "$zero".to_string(),
_ => format!("R{:?}", r.to_u8()),
}
}

trait Args {
fn print(&self) -> String;
}

impl Args for RegId {
fn print(&self) -> String {
print_reg(*self)
}
}
impl Args for Imm06 {
fn print(&self) -> String {
format!("{:#x}", self.to_u8())
}
}
impl Args for Imm12 {
fn print(&self) -> String {
format!("{:#x}", self.to_u16())
}
}
impl Args for Imm18 {
fn print(&self) -> String {
format!("{:#x}", self.to_u32())
}
}
impl Args for Imm24 {
fn print(&self) -> String {
format!("{:#x}", self.to_u32())
}
}
impl Args for () {
fn print(&self) -> String {
String::new()
}
}
impl<A: Args> Args for (A,) {
fn print(&self) -> String {
self.0.print()
}
}
impl<A: Args, B: Args> Args for (A, B) {
fn print(&self) -> String {
format!("{} {}", self.0.print(), self.1.print())
}
}
impl<A: Args, B: Args, C: Args> Args for (A, B, C) {
fn print(&self) -> String {
format!("{} {} {}", self.0.print(), self.1.print(), self.2.print())
}
}
impl<A: Args, B: Args, C: Args, D: Args> Args for (A, B, C, D) {
fn print(&self) -> String {
format!(
"{} {} {} {}",
self.0.print(),
self.1.print(),
self.2.print(),
self.3.print()
)
}
}

fn f(name: &str, args: impl Args) {
let mut line = format!("{name} {}", args.print());
let s = " ".repeat(48 - line.len());
line.push_str(&s);
print!("{line}")
}

fn print_instruction(op: &Instruction) {
match op {
Instruction::ADD(x) => f("ADD", x.unpack()),
Instruction::AND(x) => f("AND", x.unpack()),
Instruction::DIV(x) => f("DIV", x.unpack()),
Instruction::EQ(x) => f("EQ", x.unpack()),
Instruction::EXP(x) => f("EXP", x.unpack()),
Instruction::GT(x) => f("GT", x.unpack()),
Instruction::LT(x) => f("LT", x.unpack()),
Instruction::MLOG(x) => f("MLOG", x.unpack()),
Instruction::MROO(x) => f("MROO", x.unpack()),
Instruction::MOD(x) => f("MOD", x.unpack()),
Instruction::MOVE(x) => f("MOVE", x.unpack()),
Instruction::MUL(x) => f("MUL", x.unpack()),
Instruction::NOT(x) => f("NOT", x.unpack()),
Instruction::OR(x) => f("OR", x.unpack()),
Instruction::SLL(x) => f("SLL", x.unpack()),
Instruction::SRL(x) => f("SRL", x.unpack()),
Instruction::SUB(x) => f("SUB", x.unpack()),
Instruction::XOR(x) => f("XOR", x.unpack()),
Instruction::MLDV(x) => f("MLDV", x.unpack()),
Instruction::RET(x) => f("RET", x.unpack()),
Instruction::RETD(x) => f("RETD", x.unpack()),
Instruction::ALOC(x) => f("ALOC", x.unpack()),
Instruction::MCL(x) => f("MCL", x.unpack()),
Instruction::MCP(x) => f("MCP", x.unpack()),
Instruction::MEQ(x) => f("MEQ", x.unpack()),
Instruction::BHSH(x) => f("BHSH", x.unpack()),
Instruction::BHEI(x) => f("BHEI", x.unpack()),
Instruction::BURN(x) => f("BURN", x.unpack()),
Instruction::CALL(x) => f("CALL", x.unpack()),
Instruction::CCP(x) => f("CCP", x.unpack()),
Instruction::CROO(x) => f("CROO", x.unpack()),
Instruction::CSIZ(x) => f("CSIZ", x.unpack()),
Instruction::CB(x) => f("CB", x.unpack()),
Instruction::LDC(x) => f("LDC", x.unpack()),
Instruction::LOG(x) => f("LOG", x.unpack()),
Instruction::LOGD(x) => f("LOGD", x.unpack()),
Instruction::MINT(x) => f("MINT", x.unpack()),
Instruction::RVRT(x) => f("RVRT", x.unpack()),
Instruction::SCWQ(x) => f("SCWQ", x.unpack()),
Instruction::SRW(x) => f("SRW", x.unpack()),
Instruction::SRWQ(x) => f("SRWQ", x.unpack()),
Instruction::SWW(x) => f("SWW", x.unpack()),
Instruction::SWWQ(x) => f("SWWQ", x.unpack()),
Instruction::TR(x) => f("TR", x.unpack()),
Instruction::TRO(x) => f("TRO", x.unpack()),
Instruction::ECK1(x) => f("ECK1", x.unpack()),
Instruction::ECR1(x) => f("ECR1", x.unpack()),
Instruction::ED19(x) => f("ED19", x.unpack()),
Instruction::K256(x) => f("K256", x.unpack()),
Instruction::S256(x) => f("S256", x.unpack()),
Instruction::TIME(x) => f("TIME", x.unpack()),
Instruction::NOOP(_) => f("NOOP", ()),
Instruction::FLAG(x) => f("FLAG", x.unpack()),
Instruction::BAL(x) => f("BAL", x.unpack()),
Instruction::JMP(x) => f("JMP", x.unpack()),
Instruction::JNE(x) => f("JNE", x.unpack()),
Instruction::SMO(x) => f("SMO", x.unpack()),
Instruction::ADDI(x) => f("ADDI", x.unpack()),
Instruction::ANDI(x) => f("ANDI", x.unpack()),
Instruction::DIVI(x) => f("DIVI", x.unpack()),
Instruction::EXPI(x) => f("EXPI", x.unpack()),
Instruction::MODI(x) => f("MODI", x.unpack()),
Instruction::MULI(x) => f("MULI", x.unpack()),
Instruction::ORI(x) => f("ORI", x.unpack()),
Instruction::SLLI(x) => f("SLLI", x.unpack()),
Instruction::SRLI(x) => f("SRLI", x.unpack()),
Instruction::SUBI(x) => f("SUBI", x.unpack()),
Instruction::XORI(x) => f("XORI", x.unpack()),
Instruction::JNEI(x) => f("JNEI", x.unpack()),
Instruction::LB(x) => f("LB", x.unpack()),
Instruction::LW(x) => f("LW", x.unpack()),
Instruction::SB(x) => f("SB", x.unpack()),
Instruction::SW(x) => f("SW", x.unpack()),
Instruction::MCPI(x) => f("MCPI", x.unpack()),
Instruction::GTF(x) => f("GTF", x.unpack()),
Instruction::MCLI(x) => f("MCLI", x.unpack()),
Instruction::GM(x) => f("GM", x.unpack()),
Instruction::MOVI(x) => f("MOVI", x.unpack()),
Instruction::JNZI(x) => f("JNZI", x.unpack()),
Instruction::JMPF(x) => f("JMPF", x.unpack()),
Instruction::JMPB(x) => f("JMPB", x.unpack()),
Instruction::JNZF(x) => f("JNZF", x.unpack()),
Instruction::JNZB(x) => f("JNZB", x.unpack()),
Instruction::JNEF(x) => f("JNEF", x.unpack()),
Instruction::JNEB(x) => f("JNEB", x.unpack()),
Instruction::JI(x) => f("JI", x.unpack()),
Instruction::CFEI(x) => f("CFEI", x.unpack()),
Instruction::CFSI(x) => f("CFSI", x.unpack()),
Instruction::CFE(x) => f("CFE", x.unpack()),
Instruction::CFS(x) => f("CFS", x.unpack()),
Instruction::PSHL(x) => f("PSHL", x.unpack()),
Instruction::PSHH(x) => f("PSHH", x.unpack()),
Instruction::POPL(x) => f("POPL", x.unpack()),
Instruction::POPH(x) => f("POPH", x.unpack()),
Instruction::WDCM(x) => f("WDCM", x.unpack()),
Instruction::WQCM(x) => f("WQCM", x.unpack()),
Instruction::WDOP(x) => f("WDOP", x.unpack()),
Instruction::WQOP(x) => f("WQOP", x.unpack()),
Instruction::WDML(x) => f("WDML", x.unpack()),
Instruction::WQML(x) => f("WQML", x.unpack()),
Instruction::WDDV(x) => f("WDDV", x.unpack()),
Instruction::WQDV(x) => f("WQDV", x.unpack()),
Instruction::WDMD(x) => f("WDMD", x.unpack()),
Instruction::WQMD(x) => f("WQMD", x.unpack()),
Instruction::WDAM(x) => f("WDAM", x.unpack()),
Instruction::WQAM(x) => f("WQAM", x.unpack()),
Instruction::WDMM(x) => f("WDMM", x.unpack()),
Instruction::WQMM(x) => f("WQMM", x.unpack()),
Instruction::ECAL(x) => f("ECAL", x.unpack()),
}
}

Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/asm_generation/fuel/data_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct Entry {
padding: Padding,
// It is assumed, for now, that only configuration-time constants have a name. Otherwise, this
// is `None`.
name: Option<String>,
pub name: Option<String>,
}

#[derive(Clone, Debug)]
Expand Down
25 changes: 15 additions & 10 deletions sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,18 +624,22 @@ where
};

let method_name = decl.name.as_str();
code.push_str(&format!("if _method_name == \"{method_name}\" {{"));

if args_types == "()" {
code.push_str(&format!("if _method_name == \"{method_name}\" {{
let result_{method_name}: raw_slice = encode::<{return_type}>(__contract_entry_{method_name}());
__contract_ret(result_{method_name}.ptr(), result_{method_name}.len::<u8>());
}}\n"));
if args_types != "()" {
code.push_str(&format!(
"let args: {args_types} = _buffer.decode::<{args_types}>();"
));
}

code.push_str(&format!(
"let _result: {return_type} = __contract_entry_{method_name}({expanded_args});\n"
));

if return_type == "()" {
code.push_str("__contract_ret(asm() { zero: raw_ptr }, 0);\n}\n");
} else {
code.push_str(&format!("if _method_name == \"{method_name}\" {{
let args: {args_types} = decode_second_param::<{args_types}>();
let result_{method_name}: raw_slice = encode::<{return_type}>(__contract_entry_{method_name}({expanded_args}));
__contract_ret(result_{method_name}.ptr(), result_{method_name}.len::<u8>());
}}\n"));
code.push_str("let _result = encode(_result); __contract_ret(_result.ptr(), _result.len::<u8>());\n}\n");
}
}

Expand Down Expand Up @@ -674,6 +678,7 @@ where

let code = format!(
"{att} pub fn __entry() {{
let mut _buffer = BufferReader::from_second_parameter();
let _method_name = decode_first_param::<str>();
{code}
{fallback}
Expand Down
Loading

0 comments on commit eeff563

Please sign in to comment.