I think i've figured out dynamic memory layout for dynamic arrays, but could use a check on my reasoning. Consider the contract :
pragma solidity >=0.8.4;
struct state_type {
bytes b;
uint256 x_index;
uint256 x;
}
contract SolidtyStructLayout {
event EmitVal(bytes32 v);
function writeStruct() public returns(uint256 x_ind, uint256 x_val, bytes memory b) {
state_type memory local_var;
local_var.x_index = 8;
local_var.x = 9;
local_var.b = new bytes(0x20 * 3);
bytes32 v;
assembly{
v := mload(local_var)
mstore(
add(mload(local_var), 0x20),1
)
mstore(
add(mload(local_var), add(0x20, 0x20)), 2
)
mstore(
add(mload(local_var), add(0x20, 0x40)), 3)
}
emit EmitVal(v);
return(local_var.x_index , local_var.x , local_var.b);
}
}
The memory layout on execution is
{
"0x0": "0000000000000000000000000000000000000000000000000000000000000000\t????????????????????????????????",
"0x20": "0000000000000000000000000000000000000000000000000000000000000000\t????????????????????????????????",
"0x40": "0000000000000000000000000000000000000000000000000000000000000160\t????????????????????????????????",
"0x60": "0000000000000000000000000000000000000000000000000000000000000000\t????????????????????????????????",
"0x80": "00000000000000000000000000000000000000000000000000000000000000e0\t????????????????????????????????",
"0xa0": "0000000000000000000000000000000000000000000000000000000000000008\t????????????????????????????????",
"0xc0": "0000000000000000000000000000000000000000000000000000000000000009\t???????????????????????????????\t",
"0xe0": "0000000000000000000000000000000000000000000000000000000000000060\t????????????????????????????????",
"0x100": "0000000000000000000000000000000000000000000000000000000000000001\t????????????????????????????????",
"0x120": "0000000000000000000000000000000000000000000000000000000000000002\t????????????????????????????????",
"0x140": "0000000000000000000000000000000000000000000000000000000000000003\t????????????????????????????????",
"0x160": "0000000000000000000000000000000000000000000000000000000000000008\t????????????????????????????????",
"0x180": "0000000000000000000000000000000000000000000000000000000000000009\t???????????????????????????????\t",
"0x1a0": "0000000000000000000000000000000000000000000000000000000000000060\t????????????????????????????????",
"0x1c0": "0000000000000000000000000000000000000000000000000000000000000060\t????????????????????????????????",
"0x1e0": "0000000000000000000000000000000000000000000000000000000000000001\t????????????????????????????????",
"0x200": "0000000000000000000000000000000000000000000000000000000000000002\t????????????????????????????????",
"0x220": "0000000000000000000000000000000000000000000000000000000000000003\t????????????????????????????????",
"0x240": "0000000000000000000000000000000000000000000000000000000000000000\t????????????????????????????????"
}
The emit event points to address e0
as where structure begins. I was expecting the bytes array would be stored at a different location something what is done in storage. #
Due to their unpredictable size, mappings and dynamically-sized array types cannot be stored “in between” the state variables preceding and following them. Instead, they are considered to occupy only 32 bytes with regards to the rules above and the elements they contain are stored starting at a different storage slot that is computed using a Keccak-256 hash.
Is it a fair assessment that dynamic arrays (part of structs) in memory are stored in-place, i.e. length followed by elements when packed with structs?