solang/codegen/encoding/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2
3/// Any supported encoding scheme should be implemented here.
4/// The module is organized as follows:
5///
6/// - `fn abi_encode()` and `fn abi_decode()` are entry points for wherever there is
7///   something to be encoded or decoded.
8/// - `AbiEncoding` defines the encoding and decoding API and must be implemented by all schemes.
9/// - There are some helper functions to work with more complex types.
10///   Any such helper function should work fine regardless of the encoding scheme being used.
11mod 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
31/// Insert encoding instructions into the `cfg` for any `Expression` in `args`.
32/// Returns a pointer to the encoded data and the size as a 32bit integer.
33pub(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
82/// Insert decoding routines into the `cfg` for the `Expression`s in `args`.
83/// Returns a vector containing the encoded data.
84pub(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
151/// Calculate the size of a set of arguments to encoding functions
152fn 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
173/// This trait should be implemented by all encoding methods (ethabi, SCALE and Borsh), so that
174/// we have the same interface for creating encode and decode functions.
175///
176/// Note: This trait mostly reflects the situation around SCALE and Borsh encoding schemes.
177/// These two encoding schemes share only minor differences. We provide default implementations
178/// for many methods, which properly work for SCALE and Borsh encoding.
179///
180/// However, this might be less suitable for schemas vastly different than SCALE or Borsh.
181/// In the worst case scenario, you need to provide your own implementation of `fn encode(..)`,
182/// which effectively means implementing the encoding logic for any given sema `Type` on your own.
183pub(crate) trait AbiEncoding {
184    /// The width (in bits) used in size hints for dynamic size types.
185    fn size_width(
186        &self,
187        size: &Expression,
188        vartab: &mut Vartable,
189        cfg: &mut ControlFlowGraph,
190    ) -> Expression;
191
192    /// Provide generic encoding for any given `expr` into `buffer`, depending on its `Type`.
193    /// Relies on the methods encoding individual expressions (`encode_*`) to return the encoded size.
194    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                    // Structs references should not be dereferenced
245                    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    /// Write whatever is inside the given `expr` into `buffer` without any modification.
278    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    /// Encode `expr` into `buffer` as an integer.
303    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    /// Encode `expr` into `buffer` as size hint for dynamically sized datastructures.
349    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    /// Encode `expr` into `buffer` as bytes.
360    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        // ptr + offset + size_of_integer
377        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    /// Encode `expr` into `buffer` as a struct type.
397    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 the size without padding equals the size with padding, memcpy this struct directly.
410        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            // After fetching the struct member, we can encode it
455            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    /// Encode `expr` into `buffer` as an array.
469    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            // Calculate number of elements
486            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            // If the array is dynamic, we have written into the buffer its size and its elements
538            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        // In all other cases, we must loop through the array
551        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        // The offset variable minus the original offset obtains the vector size in bytes
575        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    /// Encode `expr` into `buffer` as a complex array.
604    /// This function indexes an array from its outer dimension to its inner one.
605    ///
606    /// Note: In the default implementation, `encode_array` decides when to use this method for you.
607    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 this dimension is dynamic, we must save its length before all elements
621        if dims[dimension] == ArrayLength::Dynamic && !self.is_packed() {
622            // TODO: This is wired up for the support of dynamic multidimensional arrays, like
623            // TODO: 'int[3][][4] vec', but it needs testing, as soon as Solang works with them.
624            // TODO: A discussion about this is under way here: https://github.com/hyperledger/solang/issues/932
625            // We only support dynamic arrays whose non-constant length is the outer one.
626            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            // If we are indexing the last dimension, we have an element, so we can encode it.
654            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    /// Encode `expr` into `buffer` as an external function pointer.
694    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    /// Read a value of type 'ty' from the buffer at a given offset. Returns an expression
705    /// containing the read value and the number of bytes read.
706    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                // String and Dynamic bytes are encoded as size + elements
803                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    /// Retrieve a dynamic array length from the encoded buffer. It returns the variable number in which
892    /// the length has been stored and the size width of the vector length.
893    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    /// Given the buffer and the offset, decode an array.
902    /// The function returns an expression containing the array and the number of bytes read.
903    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        // Checks if we can memcpy the elements from the buffer directly to the allocated array
916        if allow_memcpy(array_ty, ns) {
917            // Calculate number of elements
918            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            // The function decode_complex_array assumes that, if the dimension is fixed,
996            // there is no need to allocate an array
997            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            // Subtract the original offset from
1047            // the offset variable to obtain the vector size in bytes
1048            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    /// Decodes a complex array from a borsh encoded buffer
1067    /// Complex arrays are either dynamic arrays or arrays of dynamic types, like structs.
1068    /// If this is an array of structs, whose representation in memory is padded, the array is
1069    /// also complex, because it cannot be memcpy'ed
1070    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 we have a 'int[3][4][] vec', we can only validate the buffer after we have
1086        // allocated the outer dimension, i.e., we are about to read a 'int[3][4]' item.
1087        // Arrays whose elements are dynamic cannot be verified.
1088        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        // Dynamic dimensions mean that the subarray we are processing must be allocated in memory.
1109        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                // TODO: This is wired up for multidimensional dynamic arrays, but they do no work yet
1144                // Check https://github.com/hyperledger/solang/issues/932 for more information
1145                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                        // Type::Struct is a pointer to a struct. If we are dealing with a vector
1173                        // of structs, we need to dereference the pointer before storing it at a
1174                        // given vector index.
1175                        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    /// Read a struct from the buffer
1220    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 the size without padding equals the size with padding, memcpy this struct directly.
1233        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        // If it was not possible to validate the struct beforehand, we validate each field
1288        // during recursive calls to 'read_from_buffer'
1289        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    /// Calculate the size of a single codegen::Expression
1362    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    /// Calculate the size of an array
1454    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        // If the array does not have variable length elements,
1467        // we can calculate its size using a simple multiplication (direct_assessment)
1468        // i.e. 'uint8[3][] vec' has size vec.length*2*size_of(uint8)
1469        // In cases like 'uint [3][][2] v' this is not possible, as v[0] and v[1] have different sizes
1470        let direct_assessment =
1471            dyn_dims == 0 || (dyn_dims == 1 && dims.last() == Some(&ArrayLength::Dynamic));
1472
1473        // Check if the array contains only fixed sized elements
1474        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            // If the array saves primitive-type elements, its size is sizeof(type)*vec.length
1488            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    /// Calculate the size of a complex array.
1591    /// This function indexes an array from its outer dimension to its inner one and
1592    /// accounts for the encoded length size for dynamic dimensions.
1593    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 this dimension is dynamic, account for the encoded vector length variable.
1606        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    /// Retrieves the size of a struct
1677    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    /// Encoding happens in two steps. First, we look at each argument to calculate its size. If an
1719    /// argument is a storage variable, we load it and save it to a local variable.
1720    ///
1721    /// During a second pass, we copy each argument to a buffer. To copy storage variables properly into
1722    /// the buffer, we must load them from storage and save them in a local variable. As we have
1723    /// already done this, we can cache the Expression::Variable, containing the items we loaded before.
1724    /// In addition, loading from storage can be an expensive operation if it's done with large structs
1725    /// or vectors.
1726    ///
1727    /// This function serves only to cache Expression::Variable, containing items loaded from storage.
1728    /// Nothing else should be stored here.
1729    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    /// Returns if the we are packed encoding
1734    fn is_packed(&self) -> bool;
1735
1736    /// Encode constant data at compile time.
1737    ///
1738    /// Returns `None` if the data can not be encoded at compile time.
1739    fn const_encode(&self, _args: &[Expression]) -> Option<Vec<u8>> {
1740        None
1741    }
1742}
1743
1744/// This function should return the correct encoder, given the target
1745pub(crate) fn create_encoder(ns: &Namespace, packed: bool) -> Box<dyn AbiEncoding> {
1746    match &ns.target {
1747        Target::Solana => Box::new(BorshEncoding::new(packed)),
1748        // Solana utilizes Borsh encoding and Polkadot, SCALE encoding.
1749        // All other targets are using the SCALE encoding, because we have tests for a
1750        // fake Ethereum target that checks the presence of Instr::AbiDecode and
1751        // Expression::AbiEncode.
1752        // If a new target is added, this piece of code needs to change.
1753        _ => Box::new(ScaleEncoding::new(packed)),
1754    }
1755}
1756
1757/// Indexes an array. If we have 'int[3][][4] vec' and we need 'int[3][]',
1758/// 'int[3]' or 'int' (the array element) this function returns so.
1759///
1760/// * `arr` - The expression that represents the array
1761/// * `dims` - is the vector containing the array's dimensions
1762/// * `index` - is the list of indexes to use for each dimension
1763/// * `coerce_pointer_return` - forces the return of a pointer in this function.
1764///
1765/// When applying Expression::Subscript to a fixed-sized array, like 'int[3][4] vec', we
1766/// have a pointer to a 'int[3]'. If we would like to index it again, there is no need to load,
1767/// because a pointer to 'int[3]' is what the LLVM GEP instruction requires.
1768///
1769/// The underlying representation of a dynamic array is a C struct called 'struct vector'. In this
1770/// sense, a vector like 'uint16[][] vec is a 'struct vector', whose buffer elements are all pointers to
1771/// other 'struct vector's. When we index the first dimension of 'vec', we have a pointer to a pointer
1772/// to a 'struct vector', which is not compatible with LLVM GEP instruction for further indexing.
1773/// Therefore, we need an Expression::Load to obtain a pointer to 'struct vector' to be able to index
1774/// it again.
1775///
1776/// Even though all the types this function returns are pointers in the LLVM IR representation,
1777/// the argument `coerce_pointer_return` must be true when we are dealing with dynamic arrays that are
1778/// going to be the destination address of a store instruction.
1779///
1780/// In a case like this,
1781///
1782/// uint16[][] vec;
1783/// uint16[] vec1;
1784/// vec[0] = vec1;
1785///
1786/// 'vec[0]' must be a pointer to a pointer to a 'struct vector' so that the LLVM Store instruction
1787/// can be executed properly, as the value we are trying to store there is a pointer to a 'struct vector'.
1788/// In this case, we must coerce the return of a pointer. Everywhere else, the load is necessary.
1789///
1790/// `coerce_pointer_return` has not effect for fixed sized arrays.
1791fn 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        // If we are indexing the last dimension, the type should be that of the array element.
1803        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        // We should only load if the dimension is dynamic.
1821        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
1843/// This struct manages for-loops created when iterating over arrays
1844struct 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
1852/// Set up the loop to iterate over an array
1853fn 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    // Get the array length at dimension 'index'
1886    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
1930/// Closes the for-loop when iterating over an array
1931fn 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
1976/// Loads a struct member
1977fn load_struct_member(ty: Type, expr: Expression, member: usize, ns: &Namespace) -> Expression {
1978    if ty.is_fixed_reference_type(ns) {
1979        // We should not dereference a struct or fixed array
1980        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
2000/// Get the outer array length inside a variable (cannot be used for any dimension).
2001fn 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
2028/// Check if we can MemCpy a type to/from a buffer
2029fn 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                // This remainder tells us if padding is needed between the elements of an array
2035                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, // When n >= 2, the bytes must be reversed
2046        // If this is a dynamic array, we mempcy if its elements allow it and we don't need to index it.
2047        Type::Array(t, dims) if ty.is_dynamic(ns) => dims.len() == 1 && allow_memcpy(t, ns),
2048        // If the array is not dynamic, we mempcy if its elements allow it
2049        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
2055/// Calculate the number of bytes needed to memcpy an entire vector
2056fn 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
2071/// Calculate the size in bytes of a dynamic array, whose dynamic dimension is the outer.
2072/// It needs the variable saving the array's length.
2073fn 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
2093/// Allocate an array in memory and return its variable number.
2094fn 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    /// Calculate a struct size in memory considering the padding, if necessary
2124    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}