Skip to content

Commit

Permalink
Merge pull request #850 from tonlabs/opt-macros
Browse files Browse the repository at this point in the history
Optimize assembler for large inputs
  • Loading branch information
mskvortsov authored Apr 5, 2023
2 parents 83882c4 + 4522945 commit afc525f
Show file tree
Hide file tree
Showing 10 changed files with 406 additions and 320 deletions.
185 changes: 125 additions & 60 deletions Cargo.lock

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@ license-file = 'LICENSE.md'
name = 'tvm_linker'
readme = 'README.md'
repository = 'https://github.com/tonlabs/TVM-linker'
version = '0.19.6'
version = '0.20.0'

[[bin]]
name = 'tvm_linker'
path = 'src/main.rs'

[dependencies]
base64 = '0.13'
clap = '2.32'
clap = '2.33'
crc = '3.0'
ed25519 = '1.0.1'
ed25519-dalek = '1.0.1'
failure = '0.1.0'
ed25519 = '1.5'
ed25519-dalek = '1.0'
failure = '0.1'
hex = '0.4'
lazy_static = '1.4'
log = '0.4.6'
log = '0.4'
num = '0.4'
num-traits = '0.2'
rand = '0.8.5'
rand = '0.8'
regex = '1'
serde_json = '1.0.41'
serde_json = '1.0'
sha2 = '0.10'
simplelog = '0.5.3'
serde = { features = [ 'derive' ], version = '1.0.100' }
ton_abi = { git = 'https://github.com/tonlabs/ton-labs-abi.git', tag = '2.3.60' }
ton_block = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ton-labs-block.git', tag = '1.9.22' }
ton_labs_assembler = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ton-labs-assembler.git', tag = '1.2.77' }
ton_types = { git = 'https://github.com/tonlabs/ton-labs-types.git', tag = '1.12.6' }
ton_vm = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ton-labs-vm.git', tag = '1.8.108' }
simplelog = '0.6'
serde = { features = [ 'derive' ], version = '1.0' }
ton_abi = { git = 'https://github.com/tonlabs/ever-abi.git', tag = '2.3.78' }
ton_block = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ever-block.git', tag = '1.9.41' }
ton_labs_assembler = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ever-assembler.git', tag = '1.2.92' }
ton_types = { git = 'https://github.com/tonlabs/ever-types.git', tag = '2.0.0' }
ton_vm = { features = [ 'gosh' ], git = 'https://github.com/tonlabs/ever-vm.git', tag = '1.8.129' }

[dev-dependencies]
assert_cmd = '2.0.5'
Expand All @@ -49,3 +49,4 @@ similar = '2.2.0'
name = 'ton_utils'
path = 'src/lib.rs'
test = false

12 changes: 4 additions & 8 deletions src/disasm/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ use std::str::FromStr;
use failure::{bail, format_err};
use ton_block::Serializable;
use clap::ArgMatches;
use ton_types::cells_serialization::deserialize_cells_tree;
use ton_types::read_boc;
use ton_types::{Cell, HashmapE, HashmapType, SliceData, UInt256, Status};
use std::io::Cursor;

use super::{loader::Loader, types::Shape};

Expand All @@ -41,8 +40,7 @@ fn disasm_graphviz_command(m: &ArgMatches) -> Status {
.transpose()
.map_err(|e| format_err!(" failed to read tvc file: {}", e))?
.unwrap();
let mut csor = Cursor::new(tvc);
let mut roots = deserialize_cells_tree(&mut csor).unwrap();
let mut roots = read_boc(tvc).unwrap().roots;
let root = roots.remove(0).reference(0).unwrap();
match m.value_of("METHOD") {
Some(string) => {
Expand Down Expand Up @@ -137,8 +135,7 @@ fn disasm_dump_command(m: &ArgMatches) -> Status {
.transpose()
.map_err(|e| format_err!(" failed to read tvc file: {}", e))?
.unwrap();
let mut csor = Cursor::new(tvc);
let roots = deserialize_cells_tree(&mut csor).map_err(|e| format_err!("{}", e))?;
let roots = read_boc(tvc).map_err(|e| format_err!("{}", e))?.roots;
if roots.is_empty() {
println!("empty");
} else {
Expand Down Expand Up @@ -220,8 +217,7 @@ fn disasm_text_command(m: &ArgMatches) -> Status {
.transpose()
.map_err(|e| format_err!(" failed to read input file: {}", e))?
.unwrap();
let mut csor = Cursor::new(tvc);
let mut roots = deserialize_cells_tree(&mut csor).map_err(|e| format_err!("{}", e))?;
let mut roots = read_boc(tvc).map_err(|e| format_err!("{}", e))?.roots;

if m.is_present("RAW") {
print!("{}", disasm_ex(&mut SliceData::load_cell_ref(roots.get(0).unwrap())?, true));
Expand Down
6 changes: 3 additions & 3 deletions src/disasm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* limitations under the License.
*/

use ton_types::SliceData;
use ton_types::{read_boc, write_boc, SliceData};
use super::commands::{disasm, print_tree_of_cells};

use rayon::prelude::*;
Expand All @@ -32,7 +32,7 @@ fn cut_asm_hashes(asm: String) -> String {
fn round_trip_test(filename: &str, check_bin: bool) {
let raw0 = &std::fs::read_to_string(filename).unwrap();
let bin0 = base64::decode(raw0).unwrap();
let toc0 = ton_types::deserialize_tree_of_cells(&mut std::io::Cursor::new(bin0)).unwrap();
let toc0 = read_boc(bin0).unwrap().withdraw_single_root().unwrap();
let mut asm0 = disasm(&mut SliceData::load_cell(toc0.clone()).unwrap());
let toc1 = ton_labs_assembler::compile_code_to_cell(&asm0.clone()).unwrap();
let mut asm1 = disasm(&mut SliceData::load_cell(toc1.clone()).unwrap());
Expand Down Expand Up @@ -60,7 +60,7 @@ fn round_trip_test(filename: &str, check_bin: bool) {
assert!(!differ, "roundtrip difference was detected for {}", filename);

if check_bin {
let bin1 = ton_types::serialize_toc(&toc1).unwrap();
let bin1 = write_boc(&toc1).unwrap();
let raw1 = base64::encode(&bin1);
if raw0 != &raw1 {
println!("{}", asm0);
Expand Down
17 changes: 7 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use ton_block::{Deserializable, Message, StateInit, Serializable, Account, MsgAd
use std::io::Write;
use std::{path::Path};
use testcall::{call_contract, MsgInfo, TestCallParams, TraceLevel};
use ton_types::{SliceData, Result, Status, AccountId, BagOfCells, BocSerialiseMode, UInt256};
use ton_types::{SliceData, Result, Status, AccountId, UInt256, BocWriter};
use std::env;
use disasm::commands::disasm_command;
use ton_labs_assembler::{Line, compile_code_to_cell};
Expand Down Expand Up @@ -256,8 +256,7 @@ fn linker_main() -> Status {
.map_err(|e| format_err!("failed to read input file: {}", e))?;
let cell = compile_code_to_cell(code.as_str())
.map_err(|e| format_err!("failed to assemble: {}", e))?;
let mut bytes = Vec::new();
BagOfCells::with_root(&cell).write_to(&mut bytes, false)?;
let bytes = ton_types::write_boc(&cell)?;
let mut file = File::create(&output).unwrap();
file.write_all(&bytes)?;
return Ok(())
Expand Down Expand Up @@ -301,7 +300,7 @@ fn linker_main() -> Status {
sources.push(path);
let mut prog = Program::new(
ParseEngine::new(sources, abi_json)?
);
)?;

let debug = compile_matches.is_present("DEBUG");
prog.set_language(compile_matches.value_of("LANGUAGE"));
Expand Down Expand Up @@ -383,14 +382,14 @@ fn replace_command(matches: &ArgMatches) -> Status {
let mut prog_opt = None;
let code = match ParseEngine::new(sources, abi_json) {
Ok(engine) => {
let mut prog = Program::new(engine);
let mut prog = Program::new(engine)?;
let code = prog.compile_asm(false)?;
prog_opt = Some(prog);
code
}
Err(err) => {
Err(_) => {
let data = std::fs::read(path)?;
ton_types::deserialize_tree_of_cells(&mut std::io::Cursor::new(&data)).map_err(|_| err)?
ton_types::read_boc(&data)?.withdraw_single_root()?
}
};

Expand Down Expand Up @@ -712,10 +711,8 @@ fn build_message(
}

let root_cell = msg.serialize()?;
let boc = BagOfCells::with_root(&root_cell);
let mut bytes = Vec::new();
let mode = BocSerialiseMode::Generic { index: false, crc: true, cache_bits: false, flags: 0 };
boc.write_to_ex(&mut bytes, mode, None, Some(4))?;
BocWriter::with_root(&root_cell)?.write_ex(&mut bytes, false, true, None, Some(4))?;

println!("Encoded msg: {}", hex::encode(&bytes));

Expand Down
102 changes: 54 additions & 48 deletions src/methdict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,66 @@
*/
use std::collections::{BTreeMap, HashMap};
use ton_block::Serializable;
use ton_labs_assembler::{compile_code_debuggable, Lines, DbgInfo};
use ton_labs_assembler::{Lines, DbgInfo};
use ton_types::{SliceData, dictionary::HashmapE};

pub fn prepare_methods<T>(
methods: &HashMap<T, Lines>,
adjust_entry_points: bool,
) -> Result<(HashmapE, DbgInfo), (T, String)>
where
T: Clone + Default + Eq + std::fmt::Display + Serializable + std::hash::Hash,
{
let bit_len = SliceData::load_cell(T::default().serialize().unwrap()).unwrap().remaining_bits();
let mut map = HashmapE::with_bit_len(bit_len);
let mut dbg = DbgInfo::default();
insert_methods(&mut map, &mut dbg, methods, adjust_entry_points)?;
Ok((map, dbg))
}
use crate::program::Program;

pub fn insert_methods<T>(
map: &mut HashmapE,
dbg: &mut DbgInfo,
methods: &HashMap<T, Lines>,
adjust_entry_points: bool,
) -> Result<(), (T, String)>
where
T: Clone + Default + Eq + std::fmt::Display + Serializable + std::hash::Hash,
{
for pair in methods.iter() {
let key: SliceData = SliceData::load_cell(pair.0.clone().serialize()
.map_err(|e| (pair.0.clone(), format!("Failed to serialize data: {}", e)))?).unwrap();
let mut val = compile_code_debuggable(pair.1.clone()).map_err(|e| {
(pair.0.clone(), e.to_string())
})?;
if val.0.remaining_bits() <= (1023 - (32 + 10)) { // key_length + hashmap overheads
map.set(key.clone(), &val.0).map_err(|e| {
(pair.0.clone(), format!("failed to set method _name_ to dictionary: {}", e))
})?;
} else {
map.setref(key.clone(), &val.0.clone().into_cell()).map_err(|e| {
(pair.0.clone(), format!("failed to set method _name_ to dictionary: {}", e))
impl Program {
pub fn prepare_methods<T>(
&mut self,
methods: &HashMap<T, Lines>,
adjust_entry_points: bool,
) -> Result<(HashmapE, DbgInfo), (T, String)>
where
T: Clone + Default + Eq + std::fmt::Display + Serializable + std::hash::Hash,
{
let bit_len = SliceData::load_cell(T::default().serialize().unwrap()).unwrap().remaining_bits();
let mut map = HashmapE::with_bit_len(bit_len);
let mut dbg = DbgInfo::default();
self.insert_methods(&mut map, &mut dbg, methods, adjust_entry_points)?;
Ok((map, dbg))
}

pub fn insert_methods<T>(
&mut self,
map: &mut HashmapE,
dbg: &mut DbgInfo,
methods: &HashMap<T, Lines>,
adjust_entry_points: bool,
) -> Result<(), (T, String)>
where
T: Clone + Default + Eq + std::fmt::Display + Serializable + std::hash::Hash,
{
for pair in methods.iter() {
let key: SliceData = SliceData::load_cell(pair.0.clone().serialize()
.map_err(|e| (pair.0.clone(), format!("Failed to serialize data: {}", e)))?).unwrap();
let mut val = self.assemble(pair.1.clone()).map_err(|e| {
(pair.0.clone(), e.to_string())
})?;
if val.0.remaining_bits() <= (1023 - (32 + 10)) { // key_length + hashmap overheads
map.set(key.clone(), &val.0).map_err(|e| {
(pair.0.clone(), format!("failed to set method _name_ to dictionary: {}", e))
})?;
} else {
map.setref(key.clone(), &val.0.clone().into_cell()).map_err(|e| {
(pair.0.clone(), format!("failed to set method _name_ to dictionary: {}", e))
})?;
}
let id = key.clone().get_next_i32()
.map_err(|e| (pair.0.clone(), format!("Failed to decode data: {}", e)))?;
if adjust_entry_points || id < -2 || id > 0 {
let before = val.0;
let after = map.get(key)
.map_err(|e| (pair.0.clone(), format!("Failed to find key: {}", e)))?
.ok_or((pair.0.clone(), "Data is empty".to_string()))?;
adjust_debug_map(&mut val.1, before, after)
.map_err(|e| (pair.0.clone(), e))?;
}
dbg.append(&mut val.1)
}
let id = key.clone().get_next_i32()
.map_err(|e| (pair.0.clone(), format!("Failed to decode data: {}", e)))?;
if adjust_entry_points || id < -2 || id > 0 {
let before = val.0;
let after = map.get(key)
.map_err(|e| (pair.0.clone(), format!("Failed to find key: {}", e)))?
.ok_or((pair.0.clone(), "Data is empty".to_string()))?;
adjust_debug_map(&mut val.1, before, after)
.map_err(|e| (pair.0.clone(), e))?;
}
dbg.append(&mut val.1)
Ok(())
}
Ok(())
}

fn adjust_debug_map(map: &mut DbgInfo, before: SliceData, after: SliceData) -> Result<(), String> {
Expand Down
Loading

0 comments on commit afc525f

Please sign in to comment.