From the Docs, how does this operation create a new "memory end"?

mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))


library GetCode {
function at(address _addr) public view returns (bytes memory o_code) {
    assembly {
        // retrieve the size of the code, this needs assembly
        let size := extcodesize(_addr)
        // allocate output byte array - this could also be done without assembly
        // by using o_code = new bytes(size)
        o_code := mload(0x40)
        // new "memory end" including padding
        **mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))**

I can follow the operators and parse the hexadecimal, however I'm never sure if I should be performing these on underlying values or the memory address values themselves (eg. 0x20 + 0x40 = 0x60).


It explained a little later in the same documentation:

Solidity manages memory in a very simple way: There is a “free memory pointer” at position 0x40 in memory. If you want to allocate memory, just use the memory starting from where this pointer points at and update it accordingly.

An array always use the first slot to store its length and it always aligned to 32 bytes (one slot).

In pseudo code it does something like this:

  • Read free memory pointer

    array_memory = memory[0x40]
  • Calculate array size in memory, add an extra 32 bytes for the array length and round it to 32 bytes. The mathematical formula is trunc((code_size + 32 + 32 - 1) / 32) * 32. And optimized to EVM assembly it is

    array_size = (code_size + 0x20 + 0x1f) & ~0x1f
  • Update free memory pointer

    memory[0x40] += array_size
  • Thank you. The formula you included is a very elegant means of explanation. My obstacles are conceptually mapping the logical bitwise operators to the formula. (Are the operands aligned, added, converted to binary and compared bit by bit to ~0x1f (binary)? Further, what is the role of ~0x1f.) – Zach_is_my_name May 20 at 18:58
  • Search for bit mask, for example en.wikipedia.org/wiki/Mask_(computing). For example 3 has all "lower" bits set to 1 (00011), the negation ~3 will flip those bytes to 0 (11100). Now masking (x & ~3) will set the lower bits of x to 0. – Ismael May 20 at 19:11
  • Now I've got it. Appreciate your time – Zach_is_my_name May 20 at 19:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.