Skip to content

Commit 00b9d02

Browse files
authored
Improve Contract Call by not encoding method name (#7455)
## Description This is an optimisation of contract calls on top of #7440. The old version would pass a string with the method name and encode it, which is `<LEN><BYTES`. Now the compiler generates these bytes directly, avoiding encoding the method name in the first place. For that this PR creats the concept of `Literal::Binary` that does not exist in the language, yet. Would be something like `b""` in Rust. ## Improvements | Test | Before | After | Percentage | |------|--------|-------|------------| | should_pass/empty_fields_in_storage_struct (test.toml)::test_read_write_bytes | 19298 | 17533 | 9.15% | | should_pass/empty_fields_in_storage_struct (test.toml)::test_read_write_map | 14971 | 13986 | 6.58% | | should_pass/empty_fields_in_storage_struct (test.toml)::test_read_write_vec | 31061 | 29288 | 5.71% | | should_pass/language/associated_const_abi (test.toml)::test | 8789 | 7817 | 11.06% | | should_pass/language/associated_const_abi_multiple (test.toml)::test | 2421 | 2097 | 13.38% | | should_pass/language/associated_const_in_decls_of_other_constants (test.toml)::test | 870 | 709 | 18.51% | | should_pass/language/contract_caller_dynamic_address (test.toml) | 540 | 379 | 29.81% | | should_pass/language/contract_ret_intrinsic (test.toml)::test | 2133 | 1809 | 15.19% | | should_pass/language/pusha_popa_multiple_defreg (test.toml)::incorrect_pusha_popa | 819 | 624 | 23.81% | | should_pass/language/raw_identifiers (test.error_type.toml)::test | 1236 | 1075 | 13.03% | | should_pass/language/raw_identifiers (test.toml)::test | 1236 | 1075 | 13.03% | | should_pass/language/references/mutability_of_references_memcpy_bug (test.toml)::test | 1364 | 1203 | 11.80% | | should_pass/language/slice/slice_contract (test.toml)::test_success | 1338 | 1145 | 14.42% | | should_pass/language/string_slice/string_slice_contract (test.toml)::test_success | 1515 | 1322 | 12.74% | | should_pass/stdlib/storage_vec_insert (test.toml)::test_test_function | 3992 | 3831 | 4.03% | | should_pass/storage_element_key_modification (test.toml)::test_storage_key_address | 1300 | 1138 | 12.46% | | should_pass/storage_element_key_modification (test.toml)::test_storage_key_modification | 919 | 757 | 17.63% | | should_pass/storage_slot_key_calculation (test.toml)::test | 3140 | 2979 | 5.13% | | should_pass/superabi_contract_calls (test.toml)::tests | 2136 | 1812 | 15.17% | | should_pass/superabi_supertrait_same_methods (test.toml)::tests | 1097 | 936 | 14.68% | | should_pass/test_abis/abi_impl_methods_callable (test.toml)::tests | 933 | 772 | 17.26% | | should_pass/test_abis/contract_abi-auto_impl (test.toml)::tests | 933 | 772 | 17.26% | | should_pass/unit_tests/aggr_indexing (test.toml)::test1 | 6007 | 5443 | 9.39% | | should_pass/unit_tests/contract-multi-contract-calls (test.toml)::test_contract_2_call | 966 | 804 | 16.77% | | should_pass/unit_tests/contract-multi-contract-calls (test.toml)::test_contract_call | 969 | 807 | 16.72% | | should_pass/unit_tests/contract-multi-contract-calls (test.toml)::test_contract_multi_call | 1916 | 1592 | 16.91% | | should_pass/unit_tests/contract_multi_test (test.toml)::test_fail | 970 | 808 | 16.70% | | should_pass/unit_tests/contract_multi_test (test.toml)::test_success | 968 | 806 | 16.74% | | should_pass/unit_tests/script-contract-calls (test.toml)::test_contract_call | 931 | 736 | 20.95% | | should_pass/unit_tests/workspace_test (test.toml)::test_fail | 970 | 808 | 16.70% | | should_pass/unit_tests/workspace_test (test.toml)::test_success | 969 | 807 | 16.72% | ## Failed Test Only now I realized that the test for array of size zero `[u64; 0]` is not working. As this is not a useful case, I will solve it in another PR. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
1 parent fc2aed7 commit 00b9d02

File tree

14 files changed

+189
-128
lines changed

14 files changed

+189
-128
lines changed

sway-core/src/ir_generation/convert.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub(super) fn convert_literal_to_value(context: &mut Context, ast_literal: &Lite
3232
Literal::String(s) => ConstantContent::get_string(context, s.as_str().as_bytes().to_vec()),
3333
Literal::Boolean(b) => ConstantContent::get_bool(context, *b),
3434
Literal::B256(bs) => ConstantContent::get_b256(context, *bs),
35+
Literal::Binary(bytes) => ConstantContent::get_untyped_slice(context, bytes.clone()),
3536
}
3637
}
3738

@@ -50,6 +51,7 @@ pub(super) fn convert_literal_to_constant(
5051
Literal::String(s) => ConstantContent::new_string(context, s.as_str().as_bytes().to_vec()),
5152
Literal::Boolean(b) => ConstantContent::new_bool(context, *b),
5253
Literal::B256(bs) => ConstantContent::new_b256(context, *bs),
54+
Literal::Binary(bytes) => ConstantContent::new_untyped_slice(context, bytes.clone()),
5355
};
5456
Constant::unique(context, c)
5557
}

sway-core/src/ir_generation/function.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,13 @@ impl<'a> FnCompiler<'a> {
457457
))
458458
}
459459

460-
fn compile_string_slice(
460+
// Can be used for raw untyped slice and string slice
461+
fn compile_slice(
461462
&mut self,
462463
context: &mut Context,
463464
span_md_idx: Option<MetadataIndex>,
464-
string_data: Value,
465-
string_len: u64,
465+
slice_ptr: Value,
466+
slice_len: u64,
466467
) -> Result<TerminatorValue, CompileError> {
467468
let int_ty = Type::get_uint64(context);
468469
let ptr_ty = Type::get_ptr(context);
@@ -471,9 +472,9 @@ impl<'a> FnCompiler<'a> {
471472
let ptr_val = self
472473
.current_block
473474
.append(context)
474-
.cast_ptr(string_data, ptr_ty)
475+
.cast_ptr(slice_ptr, ptr_ty)
475476
.add_metadatum(context, span_md_idx);
476-
let len_val = ConstantContent::get_uint(context, 64, string_len);
477+
let len_val = ConstantContent::get_uint(context, 64, slice_len);
477478

478479
// a slice is a pointer and a length
479480
let field_types = vec![ptr_ty, int_ty];
@@ -569,7 +570,24 @@ impl<'a> FnCompiler<'a> {
569570
.append(context)
570571
.get_global(string_data_ptr);
571572
let string_len = s.as_str().len() as u64;
572-
self.compile_string_slice(context, span_md_idx, string_ptr, string_len)
573+
self.compile_slice(context, span_md_idx, string_ptr, string_len)
574+
}
575+
ty::TyExpressionVariant::Literal(Literal::Binary(bytes)) => {
576+
let data = ConstantContent::get_untyped_slice(context, bytes.clone())
577+
.get_constant(context)
578+
.unwrap();
579+
let data_ptr = self.module.new_unique_global_var(
580+
context,
581+
"__const_global".into(),
582+
data.get_content(context).ty,
583+
Some(*data),
584+
false,
585+
);
586+
587+
let slice_ptr = self.current_block.append(context).get_global(data_ptr);
588+
let slice_len = bytes.len() as u64;
589+
590+
self.compile_slice(context, span_md_idx, slice_ptr, slice_len)
573591
}
574592
ty::TyExpressionVariant::Literal(Literal::Numeric(n)) => {
575593
let implied_lit = match &*self.engines.te().get(ast_expr.return_type) {

sway-core/src/language/literal.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub enum Literal {
1919
Numeric(u64),
2020
Boolean(bool),
2121
B256([u8; 32]),
22+
Binary(Vec<u8>),
2223
}
2324

2425
impl Literal {
@@ -74,6 +75,10 @@ impl Hash for Literal {
7475
state.write_u8(8);
7576
x.hash(state);
7677
}
78+
Binary(x) => {
79+
state.write_u8(9);
80+
x.hash(state);
81+
}
7782
}
7883
}
7984
}
@@ -90,6 +95,7 @@ impl PartialEq for Literal {
9095
(Self::Numeric(l0), Self::Numeric(r0)) => l0 == r0,
9196
(Self::Boolean(l0), Self::Boolean(r0)) => l0 == r0,
9297
(Self::B256(l0), Self::B256(r0)) => l0 == r0,
98+
(Self::Binary(l0), Self::Binary(r0)) => l0 == r0,
9399
_ => false,
94100
}
95101
}
@@ -111,6 +117,11 @@ impl fmt::Display for Literal {
111117
.map(|x| x.to_string())
112118
.collect::<Vec<_>>()
113119
.join(", "),
120+
Literal::Binary(content) => content
121+
.iter()
122+
.map(|x| x.to_string())
123+
.collect::<Vec<_>>()
124+
.join(", "),
114125
};
115126
write!(f, "{s}")
116127
}
@@ -154,6 +165,7 @@ impl Literal {
154165
Literal::U256(_) => TypeInfo::UnsignedInteger(IntegerBits::V256),
155166
Literal::Boolean(_) => TypeInfo::Boolean,
156167
Literal::B256(_) => TypeInfo::B256,
168+
Literal::Binary(_) => TypeInfo::RawUntypedSlice,
157169
}
158170
}
159171
}

sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ impl Pattern {
180180
Literal::Boolean(b) => Pattern::Boolean(b),
181181
Literal::Numeric(x) => Pattern::Numeric(Range::from_single(x)),
182182
Literal::String(s) => Pattern::String(s.as_str().to_string()),
183+
Literal::Binary(_) => {
184+
unreachable!("literals cannot be expressed in the language yet")
185+
}
183186
}
184187
}
185188

sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ impl ty::TyExpression {
635635
Literal::U256(_) => type_engine.id_of_u256(),
636636
Literal::Boolean(_) => type_engine.id_of_bool(),
637637
Literal::B256(_) => type_engine.id_of_b256(),
638+
Literal::Binary(_) => type_engine.id_of_raw_slice(),
638639
};
639640
ty::TyExpression {
640641
expression: ty::TyExpressionVariant::Literal(lit),

sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,17 @@ pub(crate) fn type_check_method_application(
533533
}
534534
}
535535

536-
fn string_slice_literal(ident: &BaseIdent) -> Expression {
536+
fn method_name_literal(method_name: &BaseIdent) -> Expression {
537+
let method_name_str = method_name.as_str();
538+
let len_bytes = (method_name_str.len() as u64).to_be_bytes();
539+
540+
let mut blob = Vec::with_capacity(len_bytes.len() + method_name_str.len());
541+
blob.extend(len_bytes);
542+
blob.extend(method_name_str.as_bytes());
543+
537544
Expression {
538-
kind: ExpressionKind::Literal(Literal::String(ident.span())),
539-
span: ident.span(),
545+
kind: ExpressionKind::Literal(Literal::Binary(blob)),
546+
span: method_name.span(),
540547
}
541548
}
542549

@@ -581,7 +588,7 @@ pub(crate) fn type_check_method_application(
581588
&mut ctx,
582589
span,
583590
method.return_type.type_id,
584-
string_slice_literal(&method.name),
591+
method_name_literal(&method.name),
585592
old_arguments.first().cloned().unwrap(),
586593
args,
587594
arguments.iter().map(|x| x.1.return_type).collect(),

sway-ir/src/constant.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ impl ConstantContent {
120120
}
121121
}
122122

123+
pub fn new_untyped_slice(context: &mut Context, bytes: Vec<u8>) -> Self {
124+
ConstantContent {
125+
ty: Type::new_untyped_slice(context),
126+
value: ConstantValue::RawUntypedSlice(bytes),
127+
}
128+
}
129+
123130
pub fn new_array(context: &mut Context, elm_ty: Type, elems: Vec<ConstantContent>) -> Self {
124131
ConstantContent {
125132
ty: Type::new_array(context, elm_ty, elems.len() as u64),
@@ -181,6 +188,12 @@ impl ConstantContent {
181188
Value::new_constant(context, new_const)
182189
}
183190

191+
pub fn get_untyped_slice(context: &mut Context, value: Vec<u8>) -> Value {
192+
let new_const_contents = ConstantContent::new_untyped_slice(context, value);
193+
let new_const = Constant::unique(context, new_const_contents);
194+
Value::new_constant(context, new_const)
195+
}
196+
184197
/// `value` must be created as an array constant first, using [`Constant::new_array()`].
185198
pub fn get_array(context: &mut Context, value: ConstantContent) -> Value {
186199
assert!(value.ty.is_array(context));

sway-ir/src/irtype.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ impl Type {
140140
Self::get_type(context, &TypeContent::Pointer).expect("create_basic_types not called")
141141
}
142142

143+
pub fn new_untyped_slice(context: &mut Context) -> Type {
144+
Self::get_or_create_unique_type(context, TypeContent::Slice)
145+
}
146+
143147
/// Get string type
144148
pub fn new_string_array(context: &mut Context, len: u64) -> Type {
145149
Self::get_or_create_unique_type(context, TypeContent::StringArray(len))

sway-lib-std/src/codec.sw

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5347,7 +5347,7 @@ use ::ops::*;
53475347

53485348
pub fn contract_call<T, TArgs>(
53495349
contract_id: b256,
5350-
method_name: str,
5350+
method_name: raw_slice,
53515351
args: TArgs,
53525352
coins: u64,
53535353
asset_id: b256,
@@ -5357,11 +5357,10 @@ where
53575357
T: AbiDecode,
53585358
TArgs: AbiEncode,
53595359
{
5360-
let first_parameter = encode(method_name);
53615360
let second_parameter = encode(args);
53625361
let params = (
53635362
contract_id,
5364-
asm(a: first_parameter.ptr()) {
5363+
asm(a: method_name.ptr()) {
53655364
a: u64
53665365
},
53675366
asm(a: second_parameter.ptr()) {

sway-lsp/src/traverse/parsed_tree.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,5 +1252,6 @@ fn literal_to_symbol_kind(value: &Literal) -> SymbolKind {
12521252
Literal::String(..) => SymbolKind::StringLiteral,
12531253
Literal::B256(..) => SymbolKind::ByteLiteral,
12541254
Literal::Boolean(..) => SymbolKind::BoolLiteral,
1255+
Literal::Binary(_) => unreachable!("literals cannot be expressed in the language yet"),
12551256
}
12561257
}

0 commit comments

Comments
 (0)