Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add configurables section offset in the preamble #6709

Merged
merged 15 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use sway_core::{
transform::AttributeKind,
write_dwarf, BuildTarget, Engines, FinalizedEntry, LspConfig,
};
use sway_core::{PrintAsm, PrintIr};
use sway_core::{set_bytecode_configurables_offset, PrintAsm, PrintIr};
use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning};
use sway_features::ExperimentalFeatures;
use sway_types::constants::{CORE, PRELUDE, STD};
Expand Down Expand Up @@ -1928,7 +1928,7 @@ pub fn compile(

let errored = handler.has_errors() || (handler.has_warnings() && profile.error_on_warnings);

let compiled = match bc_res {
let mut compiled = match bc_res {
Ok(compiled) if !errored => compiled,
_ => return fail(handler),
};
Expand All @@ -1937,9 +1937,12 @@ pub fn compile(

print_warnings(engines.se(), terse_mode, &pkg.name, &warnings, &tree_type);

// Metadata to be placed into the binary.
let mut md = [0u8, 0, 0, 0, 0, 0, 0, 0];
// TODO: This should probably be in `fuel_abi_json::generate_json_abi_program`?
// If ABI requires knowing config offsets, they should be inputs to ABI gen.
if let ProgramABI::Fuel(ref mut program_abi) = program_abi {
let mut configurables_offset = compiled.bytecode.len() as u64;
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| {
Expand All @@ -1948,12 +1951,22 @@ pub fn compile(
.contains_key(&c.name)
});
// Set the actual offsets in the JSON object
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;
for (config, offset) in &compiled.named_data_section_entries_offsets {
if *offset < configurables_offset {
configurables_offset = *offset;
}
if let Some(idx) = configurables.iter().position(|c| &c.name == config) {
configurables[idx].offset = *offset;
}
}
}

md = configurables_offset.to_be_bytes();
}

// We know to set the metadata only for fuelvm right now.
if let BuildTarget::Fuel = pkg.target {
set_bytecode_configurables_offset(&mut compiled, &md);
}

metrics.bytecode_size = compiled.bytecode.len();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,62 +251,62 @@
{
"name": "BOOL",
"concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903",
"offset": 136
"offset": 240
},
{
"name": "U8",
"concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b",
"offset": 248
"offset": 352
},
{
"name": "U16",
"concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef",
"offset": 192
"offset": 296
},
{
"name": "U32",
"concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc",
"offset": 232
"offset": 336
},
{
"name": "U64",
"concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0",
"offset": 240
"offset": 344
},
{
"name": "U256",
"concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e",
"offset": 200
"offset": 304
},
{
"name": "B256",
"concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b",
"offset": 104
"offset": 208
},
{
"name": "STR_4",
"concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a",
"offset": 176
"offset": 280
},
{
"name": "TUPLE",
"concreteTypeId": "e0128f7be9902d1fe16326cafe703b52038064a7997b03ebfc1c9dd607e1536c",
"offset": 184
"offset": 288
},
{
"name": "ARRAY",
"concreteTypeId": "d9fac01ab38fe10950758ae9604da330d6406a71fda3ef1ea818121261132d56",
"offset": 88
"offset": 192
},
{
"name": "STRUCT",
"concreteTypeId": "563310524b4f4447a10d0e50556310253dfb3b5eb4b29c3773222b737c8b7075",
"offset": 160
"offset": 264
},
{
"name": "ENUM",
"concreteTypeId": "37cd1cba311039a851ac8bfa614cc41359b4ad95c8656fcef2e8f504fe7a1272",
"offset": 144
"offset": 248
}
]
}
8 changes: 4 additions & 4 deletions forc-plugins/forc-client/tests/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ async fn test_simple_deploy() {
node.kill().unwrap();
let expected = vec![DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3",
"5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -416,7 +416,7 @@ async fn test_deploy_submit_only() {
node.kill().unwrap();
let expected = vec![DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3",
"5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -462,12 +462,12 @@ async fn test_deploy_fresh_proxy() {
node.kill().unwrap();
let impl_contract = DeployedPackage::Contract(DeployedContract {
id: ContractId::from_str(
"5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3",
"5c51b8904c539700852c646c6700fddab4b80477f66e56fb2515736facd84e69",
)
.unwrap(),
proxy: Some(
ContractId::from_str(
"f0641246d72044059de56248becf345bd8553c7892df8c12d7df23f461a7f95b",
"7a78517c2c3322028db65e54893dc97958fa3d7c846a66f5675859e64f927540",
)
.unwrap(),
),
Expand Down
25 changes: 14 additions & 11 deletions forc-test/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use fuel_vm::{
self as vm,
checked_transaction::builder::TransactionBuilderExt,
interpreter::{Interpreter, NotSupportedEcal},
prelude::{Instruction, SecretKey},
prelude::SecretKey,
storage::MemoryStorage,
};
use rand::{Rng, SeedableRng};
Expand Down Expand Up @@ -246,18 +246,21 @@ impl TestExecutor {
/// The following is how the beginning of the bytecode is laid out:
///
/// ```ignore
/// [0] ji i4 ; Jumps to the data section setup.
/// [1] noop
/// [2] DATA_SECTION_OFFSET[0..32]
/// [3] DATA_SECTION_OFFSET[32..64]
/// [4] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands.
/// [5] add $$ds $$ds $is
/// [6] <first-entry-point> ; This is where we want to jump from to our test code!
/// [ 0] ji i(4 + 2) ; Jumps to the data section setup.
/// [ 1] noop
/// [ 2] DATA_SECTION_OFFSET[0..32]
/// [ 3] DATA_SECTION_OFFSET[32..64]
/// [ 4] CONFIGURABLES_OFFSET[0..32]
/// [ 5] CONFIGURABLES_OFFSET[32..64]
/// [ 6] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands.
/// [ 7] add $$ds $$ds $is
/// [ 8] <first-entry-point> ; This is where we want to jump from to our test code!
/// ```
fn patch_test_bytecode(bytecode: &[u8], test_offset: u32) -> std::borrow::Cow<[u8]> {
// TODO: Standardize this or add metadata to bytecode.
const PROGRAM_START_INST_OFFSET: u32 = 6;
const PROGRAM_START_BYTE_OFFSET: usize = PROGRAM_START_INST_OFFSET as usize * Instruction::SIZE;
// Each instruction is 4 bytes,
// so we divide the total byte-size by 4 to get the instruction offset.
const PROGRAM_START_INST_OFFSET: u32 = (sway_core::PRELUDE_SIZE_IN_BYTES / 4) as u32;
const PROGRAM_START_BYTE_OFFSET: usize = sway_core::PRELUDE_SIZE_IN_BYTES;

// If our desired entry point is the program start, no need to jump.
if test_offset == PROGRAM_START_INST_OFFSET {
Expand Down
8 changes: 8 additions & 0 deletions forc/src/cli/commands/parse_bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ pub(crate) fn exec(command: Command) -> ForcResult<()> {
parsed_raw
)
}
Err(fuel_asm::InvalidOpcode) if word_ix == 4 || word_ix == 5 => {
let parsed_raw = u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]);
format!(
"configurables offset {} ({})",
if word_ix == 4 { "lo" } else { "hi" },
parsed_raw
)
}
Ok(_) | Err(fuel_asm::InvalidOpcode) => "".into(),
};
table.add_row(Row::new(vec![
Expand Down
8 changes: 4 additions & 4 deletions forc/tests/cli_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ fn test_forc_test_raw_logs() -> Result<(), rexpect::error::Error> {
// Assert that the output is correct
process.exp_string(" test test_log_4")?;
process.exp_string("Raw logs:")?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(" test test_log_2")?;
process.exp_string("Raw logs:")?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;

process.process.exit()?;
Ok(())
Expand All @@ -74,11 +74,11 @@ fn test_forc_test_both_logs() -> Result<(), rexpect::error::Error> {
process.exp_string(" test test_log_4")?;
process.exp_string("Decoded log value: 4, log rb: 1515152261580153489")?;
process.exp_string("Raw logs:")?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(" test test_log_2")?;
process.exp_string("Decoded log value: 2, log rb: 1515152261580153489")?;
process.exp_string("Raw logs:")?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?;
process.process.exit()?;
Ok(())
}
67 changes: 55 additions & 12 deletions sway-core/src/asm_generation/finalized_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use super::{
fuel::{checks, data_section::DataSection},
ProgramABI, ProgramKind,
};
use crate::asm_generation::fuel::data_section::{DataId, Datum, Entry};
use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode};
use crate::asm_generation::fuel::data_section::{Datum, Entry, EntryName};
use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode, FuelAsmData};
use crate::decl_engine::DeclRefFunction;
use crate::source_map::SourceMap;
use crate::BuildConfig;
Expand All @@ -16,7 +16,6 @@ use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::span::Span;
use sway_types::SourceEngine;

use either::Either;
use std::{collections::BTreeMap, fmt};

/// Represents an ASM set which has had register allocation, jump elimination, and optimization
Expand Down Expand Up @@ -130,6 +129,8 @@ fn to_bytecode_mut(
{
8
}
AllocatedOpcode::AddrDataId(_, _data_id) => 8,
AllocatedOpcode::ConfigurablesOffsetPlaceholder => 8,
AllocatedOpcode::DataSectionOffsetPlaceholder => 8,
AllocatedOpcode::BLOB(count) => count.value as u64 * 4,
AllocatedOpcode::CFEI(i) | AllocatedOpcode::CFSI(i) if i.value == 0 => 0,
Expand Down Expand Up @@ -159,6 +160,29 @@ fn to_bytecode_mut(
&ops_padded
};

let mut offset_from_instr_start = 0;
for op in ops.iter() {
match &op.opcode {
AllocatedOpcode::LoadDataId(_reg, data_label)
if !data_section
.has_copy_type(data_label)
.expect("data label references non existent data -- internal error") =>
{
// For non-copy type loads, pre-insert pointers into the data_section so that
// from this point on, the data_section remains immutable. This is necessary
// so that when we take addresses of configurables, that address doesn't change
// later on if a non-configurable is added to the data-section.
let offset_bytes = data_section.data_id_to_offset(data_label) as u64;
// The -4 is because $pc is added in the *next* instruction.
let pointer_offset_from_current_instr =
offset_to_data_section_in_bytes - offset_from_instr_start + offset_bytes - 4;
data_section.append_pointer(pointer_offset_from_current_instr);
}
_ => (),
}
offset_from_instr_start += op_size_in_bytes(data_section, op);
}

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

if build_config.print_bytecode {
Expand All @@ -184,7 +208,7 @@ fn to_bytecode_mut(
offset_from_instr_start += op_size_in_bytes(data_section, op);

match fuel_op {
Either::Right(data) => {
FuelAsmData::DatasectionOffset(data) => {
if build_config.print_bytecode {
print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len());
println!(
Expand All @@ -200,7 +224,23 @@ fn to_bytecode_mut(
bytecode.extend(data.iter().cloned());
half_word_ix += 2;
}
Either::Left(instructions) => {
FuelAsmData::ConfigurablesOffset(data) => {
if build_config.print_bytecode {
print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len());
println!(
" ;; {:?}",
data
);
}

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

bytecode.extend(data.iter().cloned());
half_word_ix += 2;
}
FuelAsmData::Instructions(instructions) => {
for instruction in instructions {
// Print original source span only once
if build_config.print_bytecode_spans {
Expand Down Expand Up @@ -313,9 +353,9 @@ fn to_bytecode_mut(
};
}

for (i, entry) in data_section.value_pairs.iter().enumerate() {
let entry_offset = data_section.data_id_to_offset(&DataId(i as u32));
print_entry(indentation, offset + entry_offset, entry);
for (i, entry) in data_section.iter_all_entries().enumerate() {
let entry_offset = data_section.absolute_idx_to_offset(i);
print_entry(indentation, offset + entry_offset, &entry);
}

println!(";; --- END OF TARGET BYTECODE ---\n");
Expand All @@ -324,16 +364,19 @@ fn to_bytecode_mut(
assert_eq!(half_word_ix * 4, offset_to_data_section_in_bytes as usize);
assert_eq!(bytecode.len(), offset_to_data_section_in_bytes as usize);

let num_nonconfigurables = data_section.non_configurables.len();
let named_data_section_entries_offsets = data_section
.value_pairs
.configurables
.iter()
.enumerate()
.filter(|entry| entry.1.name.is_some())
.map(|(id, entry)| {
let EntryName::Configurable(name) = &entry.name else {
panic!("Non-configurable in configurables part of datasection");
};
(
entry.name.as_ref().unwrap().clone(),
name.clone(),
offset_to_data_section_in_bytes
+ data_section.raw_data_id_to_offset(id as u32) as u64,
+ data_section.absolute_idx_to_offset(id + num_nonconfigurables) as u64,
)
})
.collect::<BTreeMap<String, u64>>();
Expand Down
Loading
Loading