1mod borsh_encoding;
12mod buffer_validator;
13pub(super) mod scale_encoding;
14
15use crate::codegen::cfg::{ControlFlowGraph, Instr};
16use crate::codegen::encoding::borsh_encoding::BorshEncoding;
17use crate::codegen::encoding::scale_encoding::ScaleEncoding;
18use crate::codegen::expression::load_storage;
19use crate::codegen::vartable::Vartable;
20use crate::codegen::{Builtin, Expression};
21use crate::sema::ast::{ArrayLength, Namespace, RetrieveType, StructType, Type, Type::Uint};
22use crate::Target;
23use num_bigint::BigInt;
24use num_integer::Integer;
25use num_traits::{One, Zero};
26use solang_parser::pt::{Loc, Loc::Codegen};
27use std::ops::{AddAssign, MulAssign, Sub};
28
29use self::buffer_validator::BufferValidator;
30
31pub(super) fn abi_encode(
34 loc: &Loc,
35 args: Vec<Expression>,
36 ns: &Namespace,
37 vartab: &mut Vartable,
38 cfg: &mut ControlFlowGraph,
39 packed: bool,
40) -> (Expression, Expression) {
41 let mut encoder = create_encoder(ns, packed);
42 let size = calculate_size_args(&mut encoder, &args, ns, vartab, cfg);
43 let encoded_bytes = vartab.temp_name("abi_encoded", &Type::DynamicBytes);
44 let expr = Expression::AllocDynamicBytes {
45 loc: *loc,
46 ty: Type::DynamicBytes,
47 size: size.clone().into(),
48 initializer: None,
49 };
50 cfg.add(
51 vartab,
52 Instr::Set {
53 loc: *loc,
54 res: encoded_bytes,
55 expr,
56 },
57 );
58
59 let mut offset = Expression::NumberLiteral {
60 loc: *loc,
61 ty: Uint(32),
62 value: BigInt::zero(),
63 };
64 let buffer = Expression::Variable {
65 loc: *loc,
66 ty: Type::DynamicBytes,
67 var_no: encoded_bytes,
68 };
69 for (arg_no, item) in args.iter().enumerate() {
70 let advance = encoder.encode(item, &buffer, &offset, arg_no, ns, vartab, cfg);
71 offset = Expression::Add {
72 loc: *loc,
73 ty: Uint(32),
74 overflowing: false,
75 left: offset.into(),
76 right: advance.into(),
77 };
78 }
79 (buffer, size)
80}
81
82pub(super) fn abi_decode(
85 loc: &Loc,
86 buffer: &Expression,
87 types: &[Type],
88 ns: &Namespace,
89 vartab: &mut Vartable,
90 cfg: &mut ControlFlowGraph,
91 buffer_size_expr: Option<Expression>,
92) -> Vec<Expression> {
93 let buffer_size = vartab.temp_anonymous(&Uint(32));
94 if let Some(length_expression) = buffer_size_expr {
95 cfg.add(
96 vartab,
97 Instr::Set {
98 loc: Codegen,
99 res: buffer_size,
100 expr: length_expression,
101 },
102 );
103 } else {
104 cfg.add(
105 vartab,
106 Instr::Set {
107 loc: Codegen,
108 res: buffer_size,
109 expr: Expression::Builtin {
110 loc: Codegen,
111 tys: vec![Uint(32)],
112 kind: Builtin::ArrayLength,
113 args: vec![buffer.clone()],
114 },
115 },
116 );
117 }
118
119 let mut validator = BufferValidator::new(buffer_size, types);
120
121 let mut read_items: Vec<Expression> = vec![Expression::Poison; types.len()];
122 let mut offset = Expression::NumberLiteral {
123 loc: *loc,
124 ty: Uint(32),
125 value: BigInt::zero(),
126 };
127
128 validator.initialize_validation(&offset, ns, vartab, cfg);
129 let encoder = create_encoder(ns, false);
130
131 for (item_no, item) in types.iter().enumerate() {
132 validator.set_argument_number(item_no);
133 validator.validate_buffer(&offset, ns, vartab, cfg);
134 let (read_item, advance) =
135 encoder.read_from_buffer(buffer, &offset, item, &mut validator, ns, vartab, cfg);
136 read_items[item_no] = read_item;
137 offset = Expression::Add {
138 loc: *loc,
139 ty: Uint(32),
140 overflowing: false,
141 left: Box::new(offset),
142 right: Box::new(advance),
143 };
144 }
145
146 validator.validate_all_bytes_read(offset, ns, vartab, cfg);
147
148 read_items
149}
150
151fn calculate_size_args(
153 encoder: &mut Box<dyn AbiEncoding>,
154 args: &[Expression],
155 ns: &Namespace,
156 vartab: &mut Vartable,
157 cfg: &mut ControlFlowGraph,
158) -> Expression {
159 let mut size = encoder.get_expr_size(0, &args[0], ns, vartab, cfg);
160 for (i, item) in args.iter().enumerate().skip(1) {
161 let additional = encoder.get_expr_size(i, item, ns, vartab, cfg);
162 size = Expression::Add {
163 loc: Codegen,
164 ty: Uint(32),
165 overflowing: false,
166 left: size.into(),
167 right: additional.into(),
168 };
169 }
170 size
171}
172
173pub(crate) trait AbiEncoding {
184 fn size_width(
186 &self,
187 size: &Expression,
188 vartab: &mut Vartable,
189 cfg: &mut ControlFlowGraph,
190 ) -> Expression;
191
192 fn encode(
195 &mut self,
196 expr: &Expression,
197 buffer: &Expression,
198 offset: &Expression,
199 arg_no: usize,
200 ns: &Namespace,
201 vartab: &mut Vartable,
202 cfg: &mut ControlFlowGraph,
203 ) -> Expression {
204 let expr_ty = &expr.ty().unwrap_user_type(ns);
205 match expr_ty {
206 Type::Contract(_) | Type::Address(_) => {
207 self.encode_directly(expr, buffer, offset, vartab, cfg, ns.address_length.into())
208 }
209 Type::Bool => self.encode_directly(expr, buffer, offset, vartab, cfg, 1.into()),
210 Type::Uint(width) | Type::Int(width) => {
211 self.encode_int(expr, buffer, offset, ns, vartab, cfg, *width)
212 }
213 Type::Value => {
214 self.encode_directly(expr, buffer, offset, vartab, cfg, ns.value_length.into())
215 }
216 Type::Bytes(length) => {
217 self.encode_directly(expr, buffer, offset, vartab, cfg, (*length).into())
218 }
219 Type::String | Type::DynamicBytes => {
220 self.encode_bytes(expr, buffer, offset, ns, vartab, cfg)
221 }
222 Type::Enum(_) => self.encode_directly(expr, buffer, offset, vartab, cfg, 1.into()),
223 Type::Struct(ty) => {
224 self.encode_struct(expr, buffer, offset.clone(), ty, arg_no, ns, vartab, cfg)
225 }
226 Type::Slice(ty) => {
227 let dims = &[ArrayLength::Dynamic];
228 self.encode_array(
229 expr, expr_ty, ty, dims, arg_no, buffer, offset, ns, vartab, cfg,
230 )
231 }
232 Type::Array(ty, dims) => self.encode_array(
233 expr, expr_ty, ty, dims, arg_no, buffer, offset, ns, vartab, cfg,
234 ),
235 Type::ExternalFunction { .. } => {
236 self.encode_external_function(expr, buffer, offset, ns, vartab, cfg)
237 }
238 Type::FunctionSelector => {
239 let size = ns.target.selector_length().into();
240 self.encode_directly(expr, buffer, offset, vartab, cfg, size)
241 }
242 Type::Ref(r) => {
243 if let Type::Struct(ty) = &**r {
244 return self.encode_struct(
246 expr,
247 buffer,
248 offset.clone(),
249 ty,
250 arg_no,
251 ns,
252 vartab,
253 cfg,
254 );
255 }
256 let loaded = Expression::Load {
257 loc: Codegen,
258 ty: *r.clone(),
259 expr: expr.clone().into(),
260 };
261 self.encode(&loaded, buffer, offset, arg_no, ns, vartab, cfg)
262 }
263 Type::StorageRef(..) => {
264 let loaded = self.storage_cache_remove(arg_no).unwrap();
265 self.encode(&loaded, buffer, offset, arg_no, ns, vartab, cfg)
266 }
267 Type::UserType(_) | Type::Unresolved | Type::Rational | Type::Unreachable => {
268 unreachable!("Type should not exist in codegen")
269 }
270 Type::InternalFunction { .. }
271 | Type::Void
272 | Type::BufferPointer
273 | Type::Mapping(..) => unreachable!("This type cannot be encoded"),
274 }
275 }
276
277 fn encode_directly(
279 &mut self,
280 expr: &Expression,
281 buffer: &Expression,
282 offset: &Expression,
283 vartab: &mut Vartable,
284 cfg: &mut ControlFlowGraph,
285 size: BigInt,
286 ) -> Expression {
287 cfg.add(
288 vartab,
289 Instr::WriteBuffer {
290 buf: buffer.clone(),
291 offset: offset.clone(),
292 value: expr.clone(),
293 },
294 );
295 Expression::NumberLiteral {
296 loc: Codegen,
297 ty: Uint(32),
298 value: size,
299 }
300 }
301
302 fn encode_int(
304 &mut self,
305 expr: &Expression,
306 buffer: &Expression,
307 offset: &Expression,
308 ns: &Namespace,
309 vartab: &mut Vartable,
310 cfg: &mut ControlFlowGraph,
311 width: u16,
312 ) -> Expression {
313 let encoding_size = width.next_power_of_two();
314 let expr = if encoding_size != width {
315 if expr.ty().is_signed_int(ns) {
316 Expression::SignExt {
317 loc: Codegen,
318 ty: Type::Int(encoding_size),
319 expr: expr.clone().into(),
320 }
321 } else {
322 Expression::ZeroExt {
323 loc: Codegen,
324 ty: Type::Uint(encoding_size),
325 expr: expr.clone().into(),
326 }
327 }
328 } else {
329 expr.clone()
330 };
331
332 cfg.add(
333 vartab,
334 Instr::WriteBuffer {
335 buf: buffer.clone(),
336 offset: offset.clone(),
337 value: expr,
338 },
339 );
340
341 Expression::NumberLiteral {
342 loc: Codegen,
343 ty: Uint(32),
344 value: (encoding_size / 8).into(),
345 }
346 }
347
348 fn encode_size(
350 &mut self,
351 expr: &Expression,
352 buffer: &Expression,
353 offset: &Expression,
354 ns: &Namespace,
355 vartab: &mut Vartable,
356 cfg: &mut ControlFlowGraph,
357 ) -> Expression;
358
359 fn encode_bytes(
361 &mut self,
362 expr: &Expression,
363 buffer: &Expression,
364 offset: &Expression,
365 ns: &Namespace,
366 vartab: &mut Vartable,
367 cfg: &mut ControlFlowGraph,
368 ) -> Expression {
369 let len = array_outer_length(expr, vartab, cfg);
370 let (data_offset, size) = if self.is_packed() {
371 (offset.clone(), None)
372 } else {
373 let size = self.encode_size(&len, buffer, offset, ns, vartab, cfg);
374 (offset.clone().add_u32(size.clone()), Some(size))
375 };
376 let dest_address = Expression::AdvancePointer {
378 pointer: buffer.clone().into(),
379 bytes_offset: data_offset.into(),
380 };
381 cfg.add(
382 vartab,
383 Instr::MemCopy {
384 source: expr.clone(),
385 destination: dest_address,
386 bytes: len.clone(),
387 },
388 );
389 if let Some(size) = size {
390 len.add_u32(size)
391 } else {
392 len
393 }
394 }
395
396 fn encode_struct(
398 &mut self,
399 expr: &Expression,
400 buffer: &Expression,
401 mut offset: Expression,
402 struct_ty: &StructType,
403 arg_no: usize,
404 ns: &Namespace,
405 vartab: &mut Vartable,
406 cfg: &mut ControlFlowGraph,
407 ) -> Expression {
408 let size = ns.calculate_struct_non_padded_size(struct_ty);
409 if let Some(no_padding_size) = size.as_ref().filter(|no_pad| {
411 *no_pad == &struct_ty.struct_padded_size(ns) && allow_memcpy(&expr.ty(), ns)
412 }) {
413 let size = Expression::NumberLiteral {
414 loc: Codegen,
415 ty: Uint(32),
416 value: no_padding_size.clone(),
417 };
418 let dest_address = Expression::AdvancePointer {
419 pointer: buffer.clone().into(),
420 bytes_offset: offset.into(),
421 };
422 cfg.add(
423 vartab,
424 Instr::MemCopy {
425 source: expr.clone(),
426 destination: dest_address,
427 bytes: size.clone(),
428 },
429 );
430 return size;
431 }
432 let size = size.map(|no_pad| Expression::NumberLiteral {
433 loc: Codegen,
434 ty: Uint(32),
435 value: no_pad,
436 });
437
438 let qty = struct_ty.definition(ns).fields.len();
439 let first_ty = struct_ty.definition(ns).fields[0].ty.clone();
440 let loaded = load_struct_member(first_ty, expr.clone(), 0, ns);
441
442 let mut advance = self.encode(&loaded, buffer, &offset, arg_no, ns, vartab, cfg);
443 let mut runtime_size = advance.clone();
444 for i in 1..qty {
445 let ith_type = struct_ty.definition(ns).fields[i].ty.clone();
446 offset = Expression::Add {
447 loc: Codegen,
448 ty: Uint(32),
449 overflowing: false,
450 left: offset.clone().into(),
451 right: advance.into(),
452 };
453 let loaded = load_struct_member(ith_type.clone(), expr.clone(), i, ns);
454 advance = self.encode(&loaded, buffer, &offset, arg_no, ns, vartab, cfg);
456 runtime_size = Expression::Add {
457 loc: Codegen,
458 ty: Uint(32),
459 overflowing: false,
460 left: runtime_size.into(),
461 right: advance.clone().into(),
462 };
463 }
464
465 size.unwrap_or(runtime_size)
466 }
467
468 fn encode_array(
470 &mut self,
471 array: &Expression,
472 array_ty: &Type,
473 elem_ty: &Type,
474 dims: &[ArrayLength],
475 arg_no: usize,
476 buffer: &Expression,
477 offset: &Expression,
478 ns: &Namespace,
479 vartab: &mut Vartable,
480 cfg: &mut ControlFlowGraph,
481 ) -> Expression {
482 assert!(!dims.is_empty());
483
484 if allow_memcpy(array_ty, ns) {
485 let (bytes_size, offset, size_length) =
487 if matches!(dims.last(), Some(&ArrayLength::Fixed(_))) {
488 let elem_no = calculate_direct_copy_bytes_size(dims, elem_ty, ns);
489 (
490 Expression::NumberLiteral {
491 loc: Codegen,
492 ty: Uint(32),
493 value: elem_no,
494 },
495 offset.clone(),
496 None,
497 )
498 } else {
499 let value = array_outer_length(array, vartab, cfg);
500
501 let (new_offset, size_length) = if self.is_packed() {
502 (offset.clone(), None)
503 } else {
504 let encoded_size =
505 self.encode_size(&value, buffer, offset, ns, vartab, cfg);
506 (
507 offset.clone().add_u32(encoded_size.clone()),
508 Some(encoded_size),
509 )
510 };
511
512 if let Expression::Variable {
513 var_no: size_temp, ..
514 } = value
515 {
516 let size = calculate_array_bytes_size(size_temp, elem_ty, ns);
517 (size, new_offset, size_length)
518 } else {
519 unreachable!()
520 }
521 };
522
523 let dest_address = Expression::AdvancePointer {
524 pointer: buffer.clone().into(),
525 bytes_offset: offset.into(),
526 };
527
528 cfg.add(
529 vartab,
530 Instr::MemCopy {
531 source: array.clone(),
532 destination: dest_address,
533 bytes: bytes_size.clone(),
534 },
535 );
536
537 return match (size_length, self.is_packed()) {
539 (Some(len), false) => Expression::Add {
540 loc: Codegen,
541 ty: Uint(32),
542 overflowing: false,
543 left: bytes_size.into(),
544 right: len.into(),
545 },
546 _ => bytes_size,
547 };
548 }
549
550 let mut indexes: Vec<usize> = Vec::new();
552 let offset_var_no = vartab.temp_anonymous(&Uint(32));
553 cfg.add(
554 vartab,
555 Instr::Set {
556 loc: Codegen,
557 res: offset_var_no,
558 expr: offset.clone(),
559 },
560 );
561 self.encode_complex_array(
562 array,
563 arg_no,
564 dims,
565 buffer,
566 offset_var_no,
567 dims.len() - 1,
568 ns,
569 vartab,
570 cfg,
571 &mut indexes,
572 );
573
574 let offset_var = Expression::Variable {
576 loc: Codegen,
577 ty: Uint(32),
578 var_no: offset_var_no,
579 }
580 .into();
581 let sub = Expression::Subtract {
582 loc: Codegen,
583 ty: Uint(32),
584 overflowing: false,
585 left: offset_var,
586 right: offset.clone().into(),
587 };
588 cfg.add(
589 vartab,
590 Instr::Set {
591 loc: Codegen,
592 res: offset_var_no,
593 expr: sub,
594 },
595 );
596 Expression::Variable {
597 loc: Codegen,
598 ty: Uint(32),
599 var_no: offset_var_no,
600 }
601 }
602
603 fn encode_complex_array(
608 &mut self,
609 arr: &Expression,
610 arg_no: usize,
611 dims: &[ArrayLength],
612 buffer: &Expression,
613 offset_var: usize,
614 dimension: usize,
615 ns: &Namespace,
616 vartab: &mut Vartable,
617 cfg: &mut ControlFlowGraph,
618 indexes: &mut Vec<usize>,
619 ) {
620 if dims[dimension] == ArrayLength::Dynamic && !self.is_packed() {
622 let sub_array = index_array(arr.clone(), dims, indexes, false);
627
628 let size = Expression::Builtin {
629 loc: Codegen,
630 tys: vec![Uint(32)],
631 kind: Builtin::ArrayLength,
632 args: vec![sub_array],
633 };
634
635 let offset_expr = Expression::Variable {
636 loc: Codegen,
637 ty: Uint(32),
638 var_no: offset_var,
639 };
640 let encoded_size = self.encode_size(&size, buffer, &offset_expr, ns, vartab, cfg);
641 cfg.add(
642 vartab,
643 Instr::Set {
644 loc: Codegen,
645 res: offset_var,
646 expr: offset_expr.add_u32(encoded_size),
647 },
648 );
649 }
650 let for_loop = set_array_loop(arr, dims, dimension, indexes, vartab, cfg);
651 cfg.set_basic_block(for_loop.body_block);
652 if 0 == dimension {
653 let deref = index_array(arr.clone(), dims, indexes, false);
655 let offset_expr = Expression::Variable {
656 loc: Codegen,
657 ty: Uint(32),
658 var_no: offset_var,
659 };
660 let elem_size = self.encode(&deref, buffer, &offset_expr, arg_no, ns, vartab, cfg);
661 cfg.add(
662 vartab,
663 Instr::Set {
664 loc: Codegen,
665 res: offset_var,
666 expr: Expression::Add {
667 loc: Codegen,
668 ty: Uint(32),
669 overflowing: false,
670 left: elem_size.into(),
671 right: offset_expr.into(),
672 },
673 },
674 );
675 } else {
676 self.encode_complex_array(
677 arr,
678 arg_no,
679 dims,
680 buffer,
681 offset_var,
682 dimension - 1,
683 ns,
684 vartab,
685 cfg,
686 indexes,
687 )
688 }
689
690 finish_array_loop(&for_loop, vartab, cfg);
691 }
692
693 fn encode_external_function(
695 &mut self,
696 expr: &Expression,
697 buffer: &Expression,
698 offset: &Expression,
699 ns: &Namespace,
700 vartab: &mut Vartable,
701 cfg: &mut ControlFlowGraph,
702 ) -> Expression;
703
704 fn read_from_buffer(
707 &self,
708 buffer: &Expression,
709 offset: &Expression,
710 ty: &Type,
711 validator: &mut BufferValidator,
712 ns: &Namespace,
713 vartab: &mut Vartable,
714 cfg: &mut ControlFlowGraph,
715 ) -> (Expression, Expression) {
716 match ty {
717 Type::Uint(width) | Type::Int(width) => {
718 let encoding_size = width.next_power_of_two();
719
720 let size = Expression::NumberLiteral {
721 loc: Codegen,
722 ty: Uint(32),
723 value: (encoding_size / 8).into(),
724 };
725 validator.validate_offset_plus_size(offset, &size, ns, vartab, cfg);
726
727 let read_value = Expression::Builtin {
728 loc: Codegen,
729 tys: vec![ty.clone()],
730 kind: Builtin::ReadFromBuffer,
731 args: vec![buffer.clone(), offset.clone()],
732 };
733 let read_var = vartab.temp_anonymous(ty);
734
735 cfg.add(
736 vartab,
737 Instr::Set {
738 loc: Codegen,
739 res: read_var,
740 expr: if encoding_size == *width {
741 read_value
742 } else {
743 Expression::Trunc {
744 loc: Codegen,
745 ty: ty.clone(),
746 expr: Box::new(read_value),
747 }
748 },
749 },
750 );
751
752 let read_expr = Expression::Variable {
753 loc: Codegen,
754 ty: ty.clone(),
755 var_no: read_var,
756 };
757 (read_expr, size)
758 }
759
760 Type::Bool
761 | Type::Address(_)
762 | Type::Contract(_)
763 | Type::Enum(_)
764 | Type::Value
765 | Type::Bytes(_) => {
766 let read_bytes = ty.memory_size_of(ns);
767
768 let size = Expression::NumberLiteral {
769 loc: Codegen,
770 ty: Uint(32),
771 value: read_bytes,
772 };
773 validator.validate_offset_plus_size(offset, &size, ns, vartab, cfg);
774
775 let read_value = Expression::Builtin {
776 loc: Codegen,
777 tys: vec![ty.clone()],
778 kind: Builtin::ReadFromBuffer,
779 args: vec![buffer.clone(), offset.clone()],
780 };
781
782 let read_var = vartab.temp_anonymous(ty);
783 cfg.add(
784 vartab,
785 Instr::Set {
786 loc: Codegen,
787 res: read_var,
788 expr: read_value,
789 },
790 );
791
792 let read_expr = Expression::Variable {
793 loc: Codegen,
794 ty: ty.clone(),
795 var_no: read_var,
796 };
797
798 (read_expr, size)
799 }
800
801 Type::DynamicBytes | Type::String => {
802 let (array_length_var, size_length) =
804 self.retrieve_array_length(buffer, offset, vartab, cfg);
805 let array_start = offset.clone().add_u32(size_length.clone());
806 validator.validate_offset(array_start.clone(), ns, vartab, cfg);
807 let array_length = Expression::Variable {
808 loc: Codegen,
809 ty: Uint(32),
810 var_no: array_length_var,
811 };
812 let total_size = array_length.clone().add_u32(size_length);
813 validator.validate_offset(
814 offset.clone().add_u32(total_size.clone()),
815 ns,
816 vartab,
817 cfg,
818 );
819
820 let allocated_array = allocate_array(ty, array_length_var, vartab, cfg);
821 let advanced_pointer = Expression::AdvancePointer {
822 pointer: buffer.clone().into(),
823 bytes_offset: array_start.into(),
824 };
825 cfg.add(
826 vartab,
827 Instr::MemCopy {
828 source: advanced_pointer,
829 destination: Expression::Variable {
830 loc: Codegen,
831 ty: ty.clone(),
832 var_no: allocated_array,
833 },
834 bytes: array_length,
835 },
836 );
837 (
838 Expression::Variable {
839 loc: Codegen,
840 ty: ty.clone(),
841 var_no: allocated_array,
842 },
843 total_size,
844 )
845 }
846
847 Type::UserType(type_no) => {
848 let usr_type = ns.user_types[*type_no].ty.clone();
849 self.read_from_buffer(buffer, offset, &usr_type, validator, ns, vartab, cfg)
850 }
851
852 Type::ExternalFunction { .. } => {
853 self.decode_external_function(buffer, offset, ty, validator, ns, vartab, cfg)
854 }
855
856 Type::Array(elem_ty, dims) => self.decode_array(
857 buffer, offset, ty, elem_ty, dims, validator, ns, vartab, cfg,
858 ),
859
860 Type::Slice(elem_ty) => {
861 let dims = vec![ArrayLength::Dynamic];
862 self.decode_array(
863 buffer, offset, ty, elem_ty, &dims, validator, ns, vartab, cfg,
864 )
865 }
866
867 Type::Struct(struct_ty) => self.decode_struct(
868 buffer,
869 offset.clone(),
870 ty,
871 struct_ty,
872 validator,
873 ns,
874 vartab,
875 cfg,
876 ),
877
878 Type::Rational
879 | Type::Ref(_)
880 | Type::StorageRef(..)
881 | Type::BufferPointer
882 | Type::Unresolved
883 | Type::InternalFunction { .. }
884 | Type::Unreachable
885 | Type::Void
886 | Type::FunctionSelector
887 | Type::Mapping(..) => unreachable!("Type should not appear on an encoded buffer"),
888 }
889 }
890
891 fn retrieve_array_length(
894 &self,
895 buffer: &Expression,
896 offset: &Expression,
897 vartab: &mut Vartable,
898 cfg: &mut ControlFlowGraph,
899 ) -> (usize, Expression);
900
901 fn decode_array(
904 &self,
905 buffer: &Expression,
906 offset: &Expression,
907 array_ty: &Type,
908 elem_ty: &Type,
909 dims: &[ArrayLength],
910 validator: &mut BufferValidator,
911 ns: &Namespace,
912 vartab: &mut Vartable,
913 cfg: &mut ControlFlowGraph,
914 ) -> (Expression, Expression) {
915 if allow_memcpy(array_ty, ns) {
917 let (array_bytes_size, size_width, offset, var_no) =
919 if matches!(dims.last(), Some(&ArrayLength::Fixed(_))) {
920 let elem_no = calculate_direct_copy_bytes_size(dims, elem_ty, ns);
921 let allocated_vector = vartab.temp_anonymous(array_ty);
922 let expr = Expression::ArrayLiteral {
923 loc: Codegen,
924 ty: array_ty.clone(),
925 dimensions: vec![],
926 values: vec![],
927 };
928 cfg.add(
929 vartab,
930 Instr::Set {
931 loc: Codegen,
932 res: allocated_vector,
933 expr,
934 },
935 );
936 (
937 Expression::NumberLiteral {
938 loc: Codegen,
939 ty: Uint(32),
940 value: elem_no,
941 },
942 Expression::NumberLiteral {
943 loc: Codegen,
944 ty: Uint(32),
945 value: 0.into(),
946 },
947 offset.clone(),
948 allocated_vector,
949 )
950 } else {
951 let (array_length, size_width) =
952 self.retrieve_array_length(buffer, offset, vartab, cfg);
953 let array_start = offset.clone().add_u32(size_width.clone());
954 validator.validate_offset(array_start.clone(), ns, vartab, cfg);
955 (
956 calculate_array_bytes_size(array_length, elem_ty, ns),
957 size_width,
958 array_start,
959 allocate_array(array_ty, array_length, vartab, cfg),
960 )
961 };
962
963 validator.validate_offset_plus_size(&offset, &array_bytes_size, ns, vartab, cfg);
964
965 let source_address = Expression::AdvancePointer {
966 pointer: Box::new(buffer.clone()),
967 bytes_offset: Box::new(offset),
968 };
969
970 let array_expr = Expression::Variable {
971 loc: Codegen,
972 ty: array_ty.clone(),
973 var_no,
974 };
975 cfg.add(
976 vartab,
977 Instr::MemCopy {
978 source: source_address,
979 destination: array_expr.clone(),
980 bytes: array_bytes_size.clone(),
981 },
982 );
983
984 let bytes_size = if matches!(dims.last(), Some(ArrayLength::Dynamic)) {
985 array_bytes_size.add_u32(size_width)
986 } else {
987 array_bytes_size
988 };
989
990 (array_expr, bytes_size)
991 } else {
992 let mut indexes: Vec<usize> = Vec::new();
993 let array_var = vartab.temp_anonymous(array_ty);
994
995 if matches!(dims.last(), Some(ArrayLength::Fixed(_))) {
998 cfg.add(
999 vartab,
1000 Instr::Set {
1001 loc: Codegen,
1002 res: array_var,
1003 expr: Expression::ArrayLiteral {
1004 loc: Codegen,
1005 ty: array_ty.clone(),
1006 dimensions: vec![],
1007 values: vec![],
1008 },
1009 },
1010 );
1011 }
1012
1013 let offset_var = vartab.temp_anonymous(&Uint(32));
1014 cfg.add(
1015 vartab,
1016 Instr::Set {
1017 loc: Codegen,
1018 res: offset_var,
1019 expr: offset.clone(),
1020 },
1021 );
1022 let array_var_expr = Expression::Variable {
1023 loc: Codegen,
1024 ty: array_ty.clone(),
1025 var_no: array_var,
1026 };
1027 let offset_expr = Expression::Variable {
1028 loc: Codegen,
1029 ty: Uint(32),
1030 var_no: offset_var,
1031 };
1032 self.decode_complex_array(
1033 &array_var_expr,
1034 buffer,
1035 offset_var,
1036 &offset_expr,
1037 dims.len() - 1,
1038 elem_ty,
1039 dims,
1040 validator,
1041 ns,
1042 vartab,
1043 cfg,
1044 &mut indexes,
1045 );
1046 cfg.add(
1049 vartab,
1050 Instr::Set {
1051 loc: Codegen,
1052 res: offset_var,
1053 expr: Expression::Subtract {
1054 loc: Codegen,
1055 ty: Uint(32),
1056 overflowing: false,
1057 left: Box::new(offset_expr.clone()),
1058 right: Box::new(offset.clone()),
1059 },
1060 },
1061 );
1062 (array_var_expr, offset_expr)
1063 }
1064 }
1065
1066 fn decode_complex_array(
1071 &self,
1072 array_var: &Expression,
1073 buffer: &Expression,
1074 offset_var: usize,
1075 offset_expr: &Expression,
1076 dimension: usize,
1077 elem_ty: &Type,
1078 dims: &[ArrayLength],
1079 validator: &mut BufferValidator,
1080 ns: &Namespace,
1081 vartab: &mut Vartable,
1082 cfg: &mut ControlFlowGraph,
1083 indexes: &mut Vec<usize>,
1084 ) {
1085 if validator.validation_necessary()
1089 && !dims[0..(dimension + 1)]
1090 .iter()
1091 .any(|d| *d == ArrayLength::Dynamic)
1092 && !elem_ty.is_dynamic(ns)
1093 {
1094 let mut elems = BigInt::one();
1095 for item in &dims[0..(dimension + 1)] {
1096 elems.mul_assign(item.array_length().unwrap());
1097 }
1098 elems.mul_assign(elem_ty.memory_size_of(ns));
1099 let elems_size = Expression::NumberLiteral {
1100 loc: Codegen,
1101 ty: Uint(32),
1102 value: elems,
1103 };
1104 validator.validate_offset_plus_size(offset_expr, &elems_size, ns, vartab, cfg);
1105 validator.validate_array();
1106 }
1107
1108 if dims[dimension] == ArrayLength::Dynamic {
1110 let (array_length, size_length) =
1111 self.retrieve_array_length(buffer, offset_expr, vartab, cfg);
1112 let array_start = offset_expr.clone().add_u32(size_length);
1113 validator.validate_offset(array_start.clone(), ns, vartab, cfg);
1114 cfg.add(
1115 vartab,
1116 Instr::Set {
1117 loc: Codegen,
1118 res: offset_var,
1119 expr: array_start,
1120 },
1121 );
1122 let new_ty = Type::Array(Box::new(elem_ty.clone()), dims[0..(dimension + 1)].to_vec());
1123 let allocated_array = allocate_array(&new_ty, array_length, vartab, cfg);
1124
1125 if indexes.is_empty() {
1126 if let Expression::Variable { var_no, .. } = array_var {
1127 cfg.add(
1128 vartab,
1129 Instr::Set {
1130 loc: Codegen,
1131 res: *var_no,
1132 expr: Expression::Variable {
1133 loc: Codegen,
1134 ty: new_ty.clone(),
1135 var_no: allocated_array,
1136 },
1137 },
1138 );
1139 } else {
1140 unreachable!("array_var must be a variable");
1141 }
1142 } else {
1143 let sub_arr = index_array(array_var.clone(), dims, indexes, true);
1146 cfg.add(
1147 vartab,
1148 Instr::Store {
1149 dest: sub_arr,
1150 data: Expression::Variable {
1151 loc: Codegen,
1152 ty: new_ty.clone(),
1153 var_no: allocated_array,
1154 },
1155 },
1156 );
1157 }
1158 }
1159
1160 let for_loop = set_array_loop(array_var, dims, dimension, indexes, vartab, cfg);
1161 cfg.set_basic_block(for_loop.body_block);
1162 if 0 == dimension {
1163 let (read_expr, advance) =
1164 self.read_from_buffer(buffer, offset_expr, elem_ty, validator, ns, vartab, cfg);
1165 let ptr = index_array(array_var.clone(), dims, indexes, true);
1166
1167 cfg.add(
1168 vartab,
1169 Instr::Store {
1170 dest: ptr,
1171 data: if matches!(read_expr.ty(), Type::Struct(_)) {
1172 Expression::Load {
1176 loc: Codegen,
1177 ty: read_expr.ty(),
1178 expr: Box::new(read_expr),
1179 }
1180 } else {
1181 read_expr
1182 },
1183 },
1184 );
1185 cfg.add(
1186 vartab,
1187 Instr::Set {
1188 loc: Codegen,
1189 res: offset_var,
1190 expr: Expression::Add {
1191 loc: Codegen,
1192 ty: Uint(32),
1193 overflowing: false,
1194 left: Box::new(advance),
1195 right: Box::new(offset_expr.clone()),
1196 },
1197 },
1198 );
1199 } else {
1200 self.decode_complex_array(
1201 array_var,
1202 buffer,
1203 offset_var,
1204 offset_expr,
1205 dimension - 1,
1206 elem_ty,
1207 dims,
1208 validator,
1209 ns,
1210 vartab,
1211 cfg,
1212 indexes,
1213 );
1214 }
1215
1216 finish_array_loop(&for_loop, vartab, cfg);
1217 }
1218
1219 fn decode_struct(
1221 &self,
1222 buffer: &Expression,
1223 mut offset: Expression,
1224 expr_ty: &Type,
1225 struct_ty: &StructType,
1226 validator: &mut BufferValidator,
1227 ns: &Namespace,
1228 vartab: &mut Vartable,
1229 cfg: &mut ControlFlowGraph,
1230 ) -> (Expression, Expression) {
1231 let size = ns.calculate_struct_non_padded_size(struct_ty);
1232 if let Some(no_padding_size) = size.as_ref().filter(|no_pad| {
1234 *no_pad == &struct_ty.struct_padded_size(ns) && allow_memcpy(expr_ty, ns)
1235 }) {
1236 let size = Expression::NumberLiteral {
1237 loc: Codegen,
1238 ty: Uint(32),
1239 value: no_padding_size.clone(),
1240 };
1241 validator.validate_offset_plus_size(&offset, &size, ns, vartab, cfg);
1242 let source_address = Expression::AdvancePointer {
1243 pointer: Box::new(buffer.clone()),
1244 bytes_offset: Box::new(offset),
1245 };
1246 let allocated_struct = vartab.temp_anonymous(expr_ty);
1247 cfg.add(
1248 vartab,
1249 Instr::Set {
1250 loc: Codegen,
1251 res: allocated_struct,
1252 expr: Expression::StructLiteral {
1253 loc: Codegen,
1254 ty: expr_ty.clone(),
1255 values: vec![],
1256 },
1257 },
1258 );
1259 let struct_var = Expression::Variable {
1260 loc: Codegen,
1261 ty: expr_ty.clone(),
1262 var_no: allocated_struct,
1263 };
1264 cfg.add(
1265 vartab,
1266 Instr::MemCopy {
1267 source: source_address,
1268 destination: struct_var.clone(),
1269 bytes: size.clone(),
1270 },
1271 );
1272 return (struct_var, size);
1273 };
1274 let size = size.map(|no_pad| Expression::NumberLiteral {
1275 loc: Codegen,
1276 ty: Uint(32),
1277 value: no_pad,
1278 });
1279
1280 let struct_tys = struct_ty
1281 .definition(ns)
1282 .fields
1283 .iter()
1284 .map(|item| item.ty.clone())
1285 .collect::<Vec<Type>>();
1286
1287 let mut struct_validator = validator.create_sub_validator(&struct_tys);
1290
1291 let qty = struct_ty.definition(ns).fields.len();
1292
1293 if validator.validation_necessary() {
1294 struct_validator.initialize_validation(&offset, ns, vartab, cfg);
1295 }
1296
1297 let (mut read_expr, mut advance) = self.read_from_buffer(
1298 buffer,
1299 &offset,
1300 &struct_tys[0],
1301 &mut struct_validator,
1302 ns,
1303 vartab,
1304 cfg,
1305 );
1306 let mut runtime_size = advance.clone();
1307
1308 let mut read_items = vec![Expression::Poison; qty];
1309 read_items[0] = read_expr;
1310 for i in 1..qty {
1311 struct_validator.set_argument_number(i);
1312 struct_validator.validate_buffer(&offset, ns, vartab, cfg);
1313 offset = Expression::Add {
1314 loc: Codegen,
1315 ty: Uint(32),
1316 overflowing: false,
1317 left: Box::new(offset.clone()),
1318 right: Box::new(advance),
1319 };
1320 (read_expr, advance) = self.read_from_buffer(
1321 buffer,
1322 &offset,
1323 &struct_tys[i],
1324 &mut struct_validator,
1325 ns,
1326 vartab,
1327 cfg,
1328 );
1329 read_items[i] = read_expr;
1330 runtime_size = Expression::Add {
1331 loc: Codegen,
1332 ty: Uint(32),
1333 overflowing: false,
1334 left: Box::new(runtime_size),
1335 right: Box::new(advance.clone()),
1336 };
1337 }
1338
1339 let allocated_struct = vartab.temp_anonymous(expr_ty);
1340 cfg.add(
1341 vartab,
1342 Instr::Set {
1343 loc: Codegen,
1344 res: allocated_struct,
1345 expr: Expression::StructLiteral {
1346 loc: Codegen,
1347 ty: expr_ty.clone(),
1348 values: read_items,
1349 },
1350 },
1351 );
1352
1353 let struct_var = Expression::Variable {
1354 loc: Codegen,
1355 ty: expr_ty.clone(),
1356 var_no: allocated_struct,
1357 };
1358 (struct_var, size.unwrap_or(runtime_size))
1359 }
1360
1361 fn get_expr_size(
1363 &mut self,
1364 arg_no: usize,
1365 expr: &Expression,
1366 ns: &Namespace,
1367 vartab: &mut Vartable,
1368 cfg: &mut ControlFlowGraph,
1369 ) -> Expression {
1370 let ty = expr.ty().unwrap_user_type(ns);
1371 match &ty {
1372 Type::Value => Expression::NumberLiteral {
1373 loc: Codegen,
1374 ty: Uint(32),
1375 value: BigInt::from(ns.value_length),
1376 },
1377 Type::Uint(n) | Type::Int(n) => Expression::NumberLiteral {
1378 loc: Codegen,
1379 ty: Uint(32),
1380 value: BigInt::from(n.next_power_of_two() / 8),
1381 },
1382 Type::Enum(_) | Type::Contract(_) | Type::Bool | Type::Address(_) | Type::Bytes(_) => {
1383 Expression::NumberLiteral {
1384 loc: Codegen,
1385 ty: Uint(32),
1386 value: ty.memory_size_of(ns),
1387 }
1388 }
1389 Type::FunctionSelector => Expression::NumberLiteral {
1390 loc: Codegen,
1391 ty: Uint(32),
1392 value: BigInt::from(ns.target.selector_length()),
1393 },
1394 Type::Struct(struct_ty) => {
1395 self.calculate_struct_size(arg_no, expr, struct_ty, ns, vartab, cfg)
1396 }
1397 Type::Slice(ty) => {
1398 let dims = vec![ArrayLength::Dynamic];
1399 self.calculate_array_size(expr, ty, &dims, arg_no, ns, vartab, cfg)
1400 }
1401 Type::Array(ty, dims) => {
1402 self.calculate_array_size(expr, ty, dims, arg_no, ns, vartab, cfg)
1403 }
1404 Type::ExternalFunction { .. } => {
1405 let selector_len: BigInt = ns.target.selector_length().into();
1406 let address_size = Type::Address(false).memory_size_of(ns);
1407 Expression::NumberLiteral {
1408 loc: Codegen,
1409 ty: Uint(32),
1410 value: address_size + selector_len,
1411 }
1412 }
1413 Type::Ref(r) => {
1414 if let Type::Struct(struct_ty) = &**r {
1415 return self.calculate_struct_size(arg_no, expr, struct_ty, ns, vartab, cfg);
1416 }
1417 let loaded = Expression::Load {
1418 loc: Codegen,
1419 ty: *r.clone(),
1420 expr: expr.clone().into(),
1421 };
1422 self.get_expr_size(arg_no, &loaded, ns, vartab, cfg)
1423 }
1424 Type::StorageRef(_, r) => {
1425 let var = load_storage(&Codegen, r, expr.clone(), cfg, vartab);
1426 let size = self.get_expr_size(arg_no, &var, ns, vartab, cfg);
1427 self.storage_cache_insert(arg_no, var.clone());
1428 size
1429 }
1430 Type::String | Type::DynamicBytes => self.calculate_string_size(expr, vartab, cfg),
1431 Type::InternalFunction { .. }
1432 | Type::Void
1433 | Type::Unreachable
1434 | Type::BufferPointer
1435 | Type::Mapping(..) => unreachable!("This type cannot be encoded"),
1436 Type::UserType(_) | Type::Unresolved | Type::Rational => {
1437 unreachable!("Type should not exist in codegen")
1438 }
1439 }
1440 }
1441
1442 fn decode_external_function(
1443 &self,
1444 buffer: &Expression,
1445 offset: &Expression,
1446 ty: &Type,
1447 validator: &mut BufferValidator,
1448 ns: &Namespace,
1449 vartab: &mut Vartable,
1450 cfg: &mut ControlFlowGraph,
1451 ) -> (Expression, Expression);
1452
1453 fn calculate_array_size(
1455 &mut self,
1456 array: &Expression,
1457 elem_ty: &Type,
1458 dims: &Vec<ArrayLength>,
1459 arg_no: usize,
1460 ns: &Namespace,
1461 vartab: &mut Vartable,
1462 cfg: &mut ControlFlowGraph,
1463 ) -> Expression {
1464 let dyn_dims = dims.iter().filter(|d| **d == ArrayLength::Dynamic).count();
1465
1466 let direct_assessment =
1471 dyn_dims == 0 || (dyn_dims == 1 && dims.last() == Some(&ArrayLength::Dynamic));
1472
1473 let primitive_size = if elem_ty.is_primitive() && direct_assessment {
1475 Some(elem_ty.memory_size_of(ns))
1476 } else if let Type::Struct(struct_ty) = elem_ty {
1477 if direct_assessment {
1478 ns.calculate_struct_non_padded_size(struct_ty)
1479 } else {
1480 None
1481 }
1482 } else {
1483 None
1484 };
1485
1486 if let Some(compile_type_size) = primitive_size {
1487 let mut size = if let ArrayLength::Fixed(dim) = &dims.last().unwrap() {
1489 Expression::NumberLiteral {
1490 loc: Codegen,
1491 ty: Uint(32),
1492 value: dim.clone(),
1493 }
1494 } else {
1495 Expression::Builtin {
1496 loc: Codegen,
1497 tys: vec![Uint(32)],
1498 kind: Builtin::ArrayLength,
1499 args: vec![array.clone()],
1500 }
1501 };
1502
1503 for item in dims.iter().take(dims.len() - 1) {
1504 let local_size = Expression::NumberLiteral {
1505 loc: Codegen,
1506 ty: Uint(32),
1507 value: item.array_length().unwrap().clone(),
1508 };
1509 size = Expression::Multiply {
1510 loc: Codegen,
1511 ty: Uint(32),
1512 overflowing: false,
1513 left: size.into(),
1514 right: local_size.clone().into(),
1515 };
1516 }
1517
1518 let type_size = Expression::NumberLiteral {
1519 loc: Codegen,
1520 ty: Uint(32),
1521 value: compile_type_size,
1522 };
1523 let size = Expression::Multiply {
1524 loc: Codegen,
1525 ty: Uint(32),
1526 overflowing: false,
1527 left: size.into(),
1528 right: type_size.into(),
1529 };
1530 let size_var = vartab.temp_anonymous(&Uint(32));
1531 cfg.add(
1532 vartab,
1533 Instr::Set {
1534 loc: Codegen,
1535 res: size_var,
1536 expr: size,
1537 },
1538 );
1539 let size_var = Expression::Variable {
1540 loc: Codegen,
1541 ty: Uint(32),
1542 var_no: size_var,
1543 };
1544 if self.is_packed() || !matches!(&dims.last().unwrap(), ArrayLength::Dynamic) {
1545 return size_var;
1546 }
1547 let size_width = self.size_width(&size_var, vartab, cfg);
1548 Expression::Add {
1549 loc: Codegen,
1550 ty: Uint(32),
1551 overflowing: false,
1552 left: size_var.into(),
1553 right: size_width.into(),
1554 }
1555 } else {
1556 let size_var =
1557 vartab.temp_name(format!("array_bytes_size_{arg_no}").as_str(), &Uint(32));
1558 cfg.add(
1559 vartab,
1560 Instr::Set {
1561 loc: Codegen,
1562 res: size_var,
1563 expr: Expression::NumberLiteral {
1564 loc: Codegen,
1565 ty: Uint(32),
1566 value: BigInt::from(0u8),
1567 },
1568 },
1569 );
1570 let mut index_vec: Vec<usize> = Vec::new();
1571 self.calculate_complex_array_size(
1572 arg_no,
1573 array,
1574 dims,
1575 dims.len() - 1,
1576 size_var,
1577 ns,
1578 &mut index_vec,
1579 vartab,
1580 cfg,
1581 );
1582 Expression::Variable {
1583 loc: Codegen,
1584 ty: Uint(32),
1585 var_no: size_var,
1586 }
1587 }
1588 }
1589
1590 fn calculate_complex_array_size(
1594 &mut self,
1595 arg_no: usize,
1596 arr: &Expression,
1597 dims: &Vec<ArrayLength>,
1598 dimension: usize,
1599 size_var_no: usize,
1600 ns: &Namespace,
1601 indexes: &mut Vec<usize>,
1602 vartab: &mut Vartable,
1603 cfg: &mut ControlFlowGraph,
1604 ) {
1605 if !self.is_packed() && dims[dimension] == ArrayLength::Dynamic {
1607 let arr = index_array(arr.clone(), dims, indexes, false);
1608 let size = Expression::Builtin {
1609 loc: Codegen,
1610 tys: vec![Uint(32)],
1611 kind: Builtin::ArrayLength,
1612 args: vec![arr],
1613 };
1614 let size_width = self.size_width(&size, vartab, cfg);
1615 let size_var = Expression::Variable {
1616 loc: Codegen,
1617 ty: Uint(32),
1618 var_no: size_var_no,
1619 };
1620 cfg.add(
1621 vartab,
1622 Instr::Set {
1623 loc: Codegen,
1624 res: size_var_no,
1625 expr: Expression::Add {
1626 loc: Codegen,
1627 ty: Uint(32),
1628 overflowing: false,
1629 left: size_var.into(),
1630 right: size_width.into(),
1631 },
1632 },
1633 );
1634 }
1635
1636 let for_loop = set_array_loop(arr, dims, dimension, indexes, vartab, cfg);
1637 cfg.set_basic_block(for_loop.body_block);
1638 if 0 == dimension {
1639 let deref = index_array(arr.clone(), dims, indexes, false);
1640 let elem_size = self.get_expr_size(arg_no, &deref, ns, vartab, cfg);
1641 let size_var = Expression::Variable {
1642 loc: Codegen,
1643 ty: Uint(32),
1644 var_no: size_var_no,
1645 };
1646 cfg.add(
1647 vartab,
1648 Instr::Set {
1649 loc: Codegen,
1650 res: size_var_no,
1651 expr: Expression::Add {
1652 loc: Codegen,
1653 ty: Uint(32),
1654 overflowing: false,
1655 left: size_var.into(),
1656 right: elem_size.into(),
1657 },
1658 },
1659 );
1660 } else {
1661 self.calculate_complex_array_size(
1662 arg_no,
1663 arr,
1664 dims,
1665 dimension - 1,
1666 size_var_no,
1667 ns,
1668 indexes,
1669 vartab,
1670 cfg,
1671 );
1672 }
1673 finish_array_loop(&for_loop, vartab, cfg);
1674 }
1675
1676 fn calculate_struct_size(
1678 &mut self,
1679 arg_no: usize,
1680 expr: &Expression,
1681 struct_ty: &StructType,
1682 ns: &Namespace,
1683 vartab: &mut Vartable,
1684 cfg: &mut ControlFlowGraph,
1685 ) -> Expression {
1686 if let Some(struct_size) = ns.calculate_struct_non_padded_size(struct_ty) {
1687 return Expression::NumberLiteral {
1688 loc: Codegen,
1689 ty: Uint(32),
1690 value: struct_size,
1691 };
1692 }
1693 let first_type = struct_ty.definition(ns).fields[0].ty.clone();
1694 let first_field = load_struct_member(first_type, expr.clone(), 0, ns);
1695 let mut size = self.get_expr_size(arg_no, &first_field, ns, vartab, cfg);
1696 for i in 1..struct_ty.definition(ns).fields.len() {
1697 let ty = struct_ty.definition(ns).fields[i].ty.clone();
1698 let field = load_struct_member(ty.clone(), expr.clone(), i, ns);
1699 let expr_size = self.get_expr_size(arg_no, &field, ns, vartab, cfg).into();
1700 size = Expression::Add {
1701 loc: Codegen,
1702 ty: Uint(32),
1703 overflowing: false,
1704 left: size.clone().into(),
1705 right: expr_size,
1706 };
1707 }
1708 size
1709 }
1710
1711 fn calculate_string_size(
1712 &self,
1713 expr: &Expression,
1714 _vartab: &mut Vartable,
1715 _cfg: &mut ControlFlowGraph,
1716 ) -> Expression;
1717
1718 fn storage_cache_insert(&mut self, arg_no: usize, expr: Expression);
1730
1731 fn storage_cache_remove(&mut self, arg_no: usize) -> Option<Expression>;
1732
1733 fn is_packed(&self) -> bool;
1735
1736 fn const_encode(&self, _args: &[Expression]) -> Option<Vec<u8>> {
1740 None
1741 }
1742}
1743
1744pub(crate) fn create_encoder(ns: &Namespace, packed: bool) -> Box<dyn AbiEncoding> {
1746 match &ns.target {
1747 Target::Solana => Box::new(BorshEncoding::new(packed)),
1748 _ => Box::new(ScaleEncoding::new(packed)),
1754 }
1755}
1756
1757fn index_array(
1792 mut arr: Expression,
1793 dims: &[ArrayLength],
1794 indexes: &[usize],
1795 coerce_pointer_return: bool,
1796) -> Expression {
1797 let mut ty = arr.ty();
1798 let elem_ty = ty.elem_ty();
1799 let begin = dims.len() - indexes.len();
1800
1801 for i in (begin..dims.len()).rev() {
1802 let local_ty = if i == 0 {
1804 elem_ty.clone()
1805 } else {
1806 Type::Array(Box::new(elem_ty.clone()), dims[0..i].to_vec())
1807 };
1808 arr = Expression::Subscript {
1809 loc: Codegen,
1810 ty: Type::Ref(local_ty.clone().into()),
1811 array_ty: ty,
1812 expr: Box::new(arr),
1813 index: Box::new(Expression::Variable {
1814 loc: Loc::Codegen,
1815 ty: Type::Uint(32),
1816 var_no: indexes[dims.len() - i - 1],
1817 }),
1818 };
1819
1820 if i > 0 && dims[i - 1] == ArrayLength::Dynamic {
1822 arr = Expression::Load {
1823 loc: Loc::Codegen,
1824 ty: local_ty.clone(),
1825 expr: arr.into(),
1826 };
1827 }
1828
1829 ty = local_ty;
1830 }
1831
1832 if coerce_pointer_return && !matches!(arr.ty(), Type::Ref(_)) {
1833 if let Expression::Load { expr, .. } = arr {
1834 return *expr;
1835 } else {
1836 unreachable!("Expression should be a load");
1837 }
1838 }
1839
1840 arr
1841}
1842
1843struct ForLoop {
1845 pub cond_block: usize,
1846 pub next_block: usize,
1847 pub body_block: usize,
1848 pub end_block: usize,
1849 pub index: usize,
1850}
1851
1852fn set_array_loop(
1854 arr: &Expression,
1855 dims: &[ArrayLength],
1856 dimension: usize,
1857 indexes: &mut Vec<usize>,
1858 vartab: &mut Vartable,
1859 cfg: &mut ControlFlowGraph,
1860) -> ForLoop {
1861 let index_temp = vartab.temp_name(format!("for_i_{dimension}").as_str(), &Uint(32));
1862
1863 cfg.add(
1864 vartab,
1865 Instr::Set {
1866 loc: Codegen,
1867 res: index_temp,
1868 expr: Expression::NumberLiteral {
1869 loc: Codegen,
1870 ty: Uint(32),
1871 value: 0u8.into(),
1872 },
1873 },
1874 );
1875
1876 indexes.push(index_temp);
1877 let cond_block = cfg.new_basic_block("cond".to_string());
1878 let next_block = cfg.new_basic_block("next".to_string());
1879 let body_block = cfg.new_basic_block("body".to_string());
1880 let end_block = cfg.new_basic_block("end_for".to_string());
1881
1882 vartab.new_dirty_tracker();
1883 cfg.add(vartab, Instr::Branch { block: cond_block });
1884 cfg.set_basic_block(cond_block);
1885 let bound = if let ArrayLength::Fixed(dim) = &dims[dimension] {
1887 Expression::NumberLiteral {
1888 loc: Codegen,
1889 ty: Uint(32),
1890 value: dim.clone(),
1891 }
1892 } else {
1893 let sub_array = index_array(arr.clone(), dims, &indexes[..indexes.len() - 1], false);
1894 Expression::Builtin {
1895 loc: Codegen,
1896 tys: vec![Uint(32)],
1897 kind: Builtin::ArrayLength,
1898 args: vec![sub_array],
1899 }
1900 };
1901 let cond_expr = Expression::Less {
1902 loc: Codegen,
1903 signed: false,
1904 left: Expression::Variable {
1905 loc: Codegen,
1906 ty: Uint(32),
1907 var_no: index_temp,
1908 }
1909 .into(),
1910 right: bound.into(),
1911 };
1912 cfg.add(
1913 vartab,
1914 Instr::BranchCond {
1915 cond: cond_expr,
1916 true_block: body_block,
1917 false_block: end_block,
1918 },
1919 );
1920
1921 ForLoop {
1922 cond_block,
1923 next_block,
1924 body_block,
1925 end_block,
1926 index: index_temp,
1927 }
1928}
1929
1930fn finish_array_loop(for_loop: &ForLoop, vartab: &mut Vartable, cfg: &mut ControlFlowGraph) {
1932 cfg.add(
1933 vartab,
1934 Instr::Branch {
1935 block: for_loop.next_block,
1936 },
1937 );
1938 cfg.set_basic_block(for_loop.next_block);
1939 let index_var = Expression::Variable {
1940 loc: Codegen,
1941 ty: Uint(32),
1942 var_no: for_loop.index,
1943 };
1944 let one = Expression::NumberLiteral {
1945 loc: Codegen,
1946 ty: Uint(32),
1947 value: 1u8.into(),
1948 };
1949 cfg.add(
1950 vartab,
1951 Instr::Set {
1952 loc: Codegen,
1953 res: for_loop.index,
1954 expr: Expression::Add {
1955 loc: Codegen,
1956 ty: Uint(32),
1957 overflowing: false,
1958 left: index_var.into(),
1959 right: one.into(),
1960 },
1961 },
1962 );
1963 cfg.add(
1964 vartab,
1965 Instr::Branch {
1966 block: for_loop.cond_block,
1967 },
1968 );
1969 cfg.set_basic_block(for_loop.end_block);
1970 let phis = vartab.pop_dirty_tracker();
1971 cfg.set_phis(for_loop.next_block, phis.clone());
1972 cfg.set_phis(for_loop.end_block, phis.clone());
1973 cfg.set_phis(for_loop.cond_block, phis);
1974}
1975
1976fn load_struct_member(ty: Type, expr: Expression, member: usize, ns: &Namespace) -> Expression {
1978 if ty.is_fixed_reference_type(ns) {
1979 return Expression::StructMember {
1981 loc: Codegen,
1982 ty,
1983 expr: expr.into(),
1984 member,
1985 };
1986 }
1987 let s = Expression::StructMember {
1988 loc: Codegen,
1989 ty: Type::Ref(ty.clone().into()),
1990 expr: expr.into(),
1991 member,
1992 };
1993 Expression::Load {
1994 loc: Codegen,
1995 ty,
1996 expr: s.into(),
1997 }
1998}
1999
2000fn array_outer_length(
2002 arr: &Expression,
2003 vartab: &mut Vartable,
2004 cfg: &mut ControlFlowGraph,
2005) -> Expression {
2006 let get_size = Expression::Builtin {
2007 loc: Codegen,
2008 tys: vec![Uint(32)],
2009 kind: Builtin::ArrayLength,
2010 args: vec![arr.clone()],
2011 };
2012 let array_length = vartab.temp_anonymous(&Uint(32));
2013 cfg.add(
2014 vartab,
2015 Instr::Set {
2016 loc: Codegen,
2017 res: array_length,
2018 expr: get_size,
2019 },
2020 );
2021 Expression::Variable {
2022 loc: Codegen,
2023 ty: Uint(32),
2024 var_no: array_length,
2025 }
2026}
2027
2028fn allow_memcpy(ty: &Type, ns: &Namespace) -> bool {
2030 match ty {
2031 Type::Struct(struct_ty) => {
2032 if let Some(no_padded_size) = ns.calculate_struct_non_padded_size(struct_ty) {
2033 let padded_size = struct_ty.struct_padded_size(ns);
2034 let remainder = padded_size.mod_floor(&ty.struct_elem_alignment(ns));
2036 let ty_allowed = struct_ty
2037 .definition(ns)
2038 .fields
2039 .iter()
2040 .all(|f| allow_memcpy(&f.ty, ns));
2041 return no_padded_size == padded_size && remainder.is_zero() && ty_allowed;
2042 }
2043 false
2044 }
2045 Type::Bytes(n) => *n < 2, Type::Array(t, dims) if ty.is_dynamic(ns) => dims.len() == 1 && allow_memcpy(t, ns),
2048 Type::Array(t, _) => allow_memcpy(t, ns),
2050 Type::UserType(t) => allow_memcpy(&ns.user_types[*t].ty, ns),
2051 _ => ty.is_primitive(),
2052 }
2053}
2054
2055fn calculate_direct_copy_bytes_size(
2057 dims: &[ArrayLength],
2058 elem_ty: &Type,
2059 ns: &Namespace,
2060) -> BigInt {
2061 let mut elem_no = BigInt::one();
2062 for item in dims {
2063 debug_assert!(matches!(item, &ArrayLength::Fixed(_)));
2064 elem_no.mul_assign(item.array_length().unwrap());
2065 }
2066 let bytes = elem_ty.memory_size_of(ns);
2067 elem_no.mul_assign(bytes);
2068 elem_no
2069}
2070
2071fn calculate_array_bytes_size(length_var: usize, elem_ty: &Type, ns: &Namespace) -> Expression {
2074 let var = Expression::Variable {
2075 loc: Codegen,
2076 ty: Uint(32),
2077 var_no: length_var,
2078 };
2079 let size = Expression::NumberLiteral {
2080 loc: Codegen,
2081 ty: Uint(32),
2082 value: elem_ty.memory_size_of(ns),
2083 };
2084 Expression::Multiply {
2085 loc: Codegen,
2086 ty: Uint(32),
2087 overflowing: false,
2088 left: var.into(),
2089 right: size.into(),
2090 }
2091}
2092
2093fn allocate_array(
2095 ty: &Type,
2096 length_variable: usize,
2097 vartab: &mut Vartable,
2098 cfg: &mut ControlFlowGraph,
2099) -> usize {
2100 let array_var = vartab.temp_anonymous(ty);
2101 let length_var = Expression::Variable {
2102 loc: Codegen,
2103 ty: Uint(32),
2104 var_no: length_variable,
2105 };
2106 cfg.add(
2107 vartab,
2108 Instr::Set {
2109 loc: Codegen,
2110 res: array_var,
2111 expr: Expression::AllocDynamicBytes {
2112 loc: Codegen,
2113 ty: ty.clone(),
2114 size: length_var.into(),
2115 initializer: None,
2116 },
2117 },
2118 );
2119 array_var
2120}
2121
2122impl StructType {
2123 fn struct_padded_size(&self, ns: &Namespace) -> BigInt {
2125 let mut total = BigInt::zero();
2126 for item in &self.definition(ns).fields {
2127 let ty_align = item.ty.struct_elem_alignment(ns);
2128 let remainder = total.mod_floor(&ty_align);
2129 if !remainder.is_zero() {
2130 let padding = ty_align.sub(remainder);
2131 total.add_assign(padding);
2132 }
2133 total.add_assign(item.ty.memory_size_of(ns));
2134 }
2135 total
2136 }
2137}